aboutsummaryrefslogtreecommitdiff
path: root/src/appl/gssftp/ftp
diff options
context:
space:
mode:
authorMark Eichin <eichin@mit.edu>1996-01-14 08:33:16 +0000
committerMark Eichin <eichin@mit.edu>1996-01-14 08:33:16 +0000
commit4233c6f3143639f164290a00eb0ffe720a32b9bc (patch)
tree11e611f0bdc83991fc573882148217df9f1db53d /src/appl/gssftp/ftp
parent347ed3cc833b7d119f51f82c78aafe9e420073af (diff)
downloadkrb5-4233c6f3143639f164290a00eb0ffe720a32b9bc.zip
krb5-4233c6f3143639f164290a00eb0ffe720a32b9bc.tar.gz
krb5-4233c6f3143639f164290a00eb0ffe720a32b9bc.tar.bz2
Cygnus implementation of GSSAPI-based ftp client and server.
See README.gssftp for history and details. Bugs, comments to <eichin@cygnus.com>. Be sure to forward any changes made at MIT as well. git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@7312 dc483132-0cff-0310-8789-dd5450dbe970
Diffstat (limited to 'src/appl/gssftp/ftp')
-rw-r--r--src/appl/gssftp/ftp/ChangeLog219
-rw-r--r--src/appl/gssftp/ftp/Makefile.in52
-rw-r--r--src/appl/gssftp/ftp/cmds.c2337
-rw-r--r--src/appl/gssftp/ftp/cmdtab.c225
-rw-r--r--src/appl/gssftp/ftp/configure.in12
-rw-r--r--src/appl/gssftp/ftp/domacro.c153
-rw-r--r--src/appl/gssftp/ftp/ftp.M1200
-rw-r--r--src/appl/gssftp/ftp/ftp.c2147
-rw-r--r--src/appl/gssftp/ftp/ftp_var.h139
-rw-r--r--src/appl/gssftp/ftp/getpass.c73
-rw-r--r--src/appl/gssftp/ftp/glob.c698
-rw-r--r--src/appl/gssftp/ftp/main.c553
-rw-r--r--src/appl/gssftp/ftp/pathnames.h37
-rw-r--r--src/appl/gssftp/ftp/pclose.c127
-rw-r--r--src/appl/gssftp/ftp/radix.c163
-rw-r--r--src/appl/gssftp/ftp/ruserpass.c283
-rw-r--r--src/appl/gssftp/ftp/secure.c382
-rw-r--r--src/appl/gssftp/ftp/secure.h4
18 files changed, 8804 insertions, 0 deletions
diff --git a/src/appl/gssftp/ftp/ChangeLog b/src/appl/gssftp/ftp/ChangeLog
new file mode 100644
index 0000000..f1ff4ff
--- /dev/null
+++ b/src/appl/gssftp/ftp/ChangeLog
@@ -0,0 +1,219 @@
+Sun Jan 14 01:54:35 1996 Bill Schoofs <wjs@cray.com>
+
+ * Makefile.in (DEFINES): define NOCONFIDENTIAL for future use.
+ * ftp.c (command): recognize 533, not 402, for 'server unwilling
+ to accept'
+ (getreply): recognize 633 for confidential reply, and then don't
+ support it.
+
+Tue Jan 2 19:17:47 1996 Mark Eichin <eichin@cygnus.com>
+
+ * pclose.c: test HAVE_GETDTABLESIZE instead of hpux.
+ * configure.in: set HAVE_GETDTABLESIZE.
+
+Fri Oct 20 11:59:32 1995 Mark W. Eichin <eichin@cygnus.com>
+
+ * ftp.c (do_auth): synthesize channel bindings from myctladdr and
+ hisctladdr, based on changes pending for draft 9.
+
+Thu Oct 19 04:47:36 1995 Mark W. Eichin <eichin@cygnus.com>
+
+ * configure.in: check for POSIX_TERMIOS just like appl/bsd does.
+
+Wed Oct 4 19:24:39 1995 Mark Eichin <eichin@cygnus.com>
+
+ * ftp, pclose, ruserpass.c, secure.c: don't ever declare malloc.
+
+Sun Oct 1 03:30:30 1995 Mark Eichin <eichin@cygnus.com>
+
+ * ftp.c (do_auth): accept ADAT 3yz response. Clean up loops, add
+ lots of debugging messages.
+
+Sun Oct 1 00:56:55 1995 Mark Eichin <eichin@cygnus.com>
+
+ * Makefile.in: use FTP_BUFSIZ everywhere and make it large for
+ now.
+ * ftp.c: only look at "host" for now. Report error parsing
+ name. Handle gssapi error reporting better.
+
+
+Sat Sep 30 22:26:37 1995 Mark Eichin <eichin@cygnus.com>
+
+ * ftp.c, secure.c: correct gssapi includes. Fix some typos and
+ missing declarations.
+
+Sat Sep 30 21:31:09 1995 Mark Eichin <eichin@cygnus.com>
+
+ * Makefile.in (depend, install): change to double colon rules.
+ * cmds.c: no conf.h, check HAVE_GETCWD, use krb5_sigtype.
+ * configure.in: check KRB5_SIGTYPE, CHECK_SIGPROCMASK,
+ CHECK_WAIT_TYPE, and getcwd.
+ * ftp.c: no conf.h, use krb5_sigtype.
+ (secure_command): use user_gss_error.
+ (do_auth): cycle through gss_services.
+ (user_gss_error): new function, decomposes GSSAPI errors and sends
+ them to standard error.
+ (secure_gss_error): hook for secure.c common functions to get the
+ correct error routine.
+ * getpass.c, main.c: no conf.h, use krb5_sigtype.
+ * pclose.c: no conf.h, use krb5_sigtype.
+ (mypclose): obey USE_SIGPROCMASK.
+ * secure.c (secure_getbyte): use generic secure_gss_error.
+
+Sat Sep 30 16:43:28 1995 Mark Eichin <eichin@cygnus.com>
+
+ * configure.in, Makefile.in: new files for port to GSSAPI and
+ build within the Kerberos V5 build tree.
+ * ftp.c, secure.c: GSSAPI authentication changes based on the IETF
+ CAT working group ***DRAFT*** FTP Security specification, draft
+ number 8, appendix I.
+
+
+**** previous change logs from CNS V4 modifications of Steve Lunt's
+ draft-3 ftp client, which this is based on. ****
+
+Wed Jul 26 21:01:42 1995 Ken Raeburn <raeburn@cygnus.com>
+
+ * domacro.c: Include string.h.
+ * secure.c: Ditto.
+
+Mon Jul 10 14:54:41 1995 Michael Meissner <meissner@tiktok.cygnus.com>
+
+ * glob.c (matchdir): #if 0 code that uses a private member of the
+ DIR structure to check whether a filename passed to opendir is a
+ directory or not.
+
+Fri May 26 19:36:12 1995 Mark Eichin <eichin@cygnus.com>
+
+ * glob.c (matchdir): open "." explicitly if gpath is null.
+
+Fri May 19 16:11:07 1995 Mark Eichin <eichin@cygnus.com>
+
+ * ftp.c (ptransfer): be sure that printf(%g) gets a float, not an
+ implicit double, by doing the whole calculation in the variable.
+
+Thu Feb 2 13:40:04 1995 Ian Lance Taylor <ian@cygnus.com>
+
+ * ftp.c: Don't try to use IP_TOS if the IP_TOS argument
+ (IPTOS_LOWDELAY, etc.) is not defined.
+
+Wed Jan 18 14:07:33 1995 Ian Lance Taylor <ian@sanguine.cygnus.com>
+
+ * ftp.1: Include man1/tmac.doc.
+
+ * ftp.c (initconn): If the PASV command is rejected, turn off
+ passive mode and try again.
+
+Wed Jan 4 11:21:34 1995 Ian Lance Taylor <ian@tweedledumb.cygnus.com>
+
+ * cmds.c, ftp.c: Use mygetpass instead of getpass.
+
+ * ruserpass.c: Don't include <utmp.h>. Don't declare getlogin,
+ getpass, or getuttmp.
+
+Thu Dec 29 15:19:44 1994 Mark Eichin <eichin@cygnus.com>
+
+ * cmds.c (setpeer): add || defined(linux) to the NBBY == 8 check,
+ since this code is appropriate under linux.
+
+Thu Dec 29 14:11:37 1994 Mark Eichin <eichin@cygnus.com>
+
+ * cmds.c (siteidle): renamed idle() to avoid conflict with linux
+ idle(void).
+ * cmdtab.c: rename declaration and cmdtab entry.
+
+Tue Dec 27 13:29:08 1994 Ian Lance Taylor <ian@sanguine.cygnus.com>
+
+ * ftp.c: If STDARG is defined, or if __STDC__ is defined and
+ VARARGS is not defined, include <stdarg.h>, instead of
+ <varargs.h>.
+ (command): Use <stdarg.h> routines if STDARG || (__STDC__ && !
+ VARARGS).
+ (secure_error): Likewise.
+ * ftp_var.h (command): Declare if STDARG || (__STDC__ && !
+ VARARGS).
+ * secure.c (secure_error): Likewise.
+
+ * secure.h (hisaddr): Define as hisdataaddr.
+ * ftp.c (hisdataaddr): New global variable.
+ (initconn): Set hisdataaddr to data_addr.
+ (dataconn): Use hisdataaddr instead of local variable from.
+
+Fri Dec 23 15:18:12 1994 Ian Lance Taylor <ian@sanguine.cygnus.com>
+
+ * cmds.c (unix): Define if _AIX is defined (AIX compiler does not
+ predefine unix).
+
+ * ftp.c (login): When choosing the default login name, use the
+ values of the environment variables LOGNAME and then USER in
+ preference to calling getlogin.
+
+Thu Dec 22 14:59:34 1994 Ian Lance Taylor <ian@sanguine.cygnus.com>
+
+ * cmds.c (gettype): Sometimes type will be zero, which requires
+ special handling.
+
+ * main.c: Include <krb.h>.
+ (main): Support new option: -k.
+ * ftp.c (realm): New global variable.
+ (do_auth): Remove local variable realm; use new global instead.
+ Don't call krb_realmofhost if realm is set.
+ * ftp.1: Document -k.
+
+Fri Dec 16 10:53:08 1994 Ian Lance Taylor <ian@cygnus.com>
+
+ Fixes for Alpha OSF/1:
+ * cmds.c: Redefine sig_t to my_sig_t to avoid header file
+ conflict.
+ * ftp.c: Likewise.
+
+ Fixes for SCO:
+ * cmdtab.c: Include <stdio.h> before ftp_var.h.
+ * domacro.c: Move include of <stdio.h> before include of
+ ftp_var.h. Don't include <sys/ttychars.h>.
+ * main.c: Move include of <stdio.h> before include of ftp_var.h.
+
+ Fixes for AIX:
+ * cmds.c (mput): Use 0 instead of NULL when an integer is
+ expected.
+ (getit, mget): Likewise.
+ * ftp_var.h (strncpy, strncat, strcat, strcpy): Don't declare.
+ * ruserpass.c (strcpy): Don't declare.
+ * secure.c: Include <netinet/in.h>.
+
+ Fixes for Irix 4:
+ * ftp_var.h: Unless DEFINITIONS is defined, declare variables
+ rather than defining them.
+ * ftp.c: Define DEFINITIONS before including ftp_var.h.
+ (recvrequest): If NOSTBLKSIZE is defined, use BUFSIZ instead of
+ st_blksize.
+ * getpass.c: Put note after #endif in /* */
+ * pclose.c: Likewise.
+ * ruserpass.c (token): Move before ruserpass.
+ (ruserpass): Don't declare token.
+
+ General fixes to make it compile on Solaris: Use sigtype for
+ signal handler return values, including conf.h where needed. Add
+ a dummy argument to signal handler functions. Replace index,
+ rindex, bzero and bcopy with ANSI C functions. Cast Kerberos
+ routine arguments to avoid warnings. Also:
+ * cmds.c: Include <string.h>. If POSIX is defined, include
+ unistd.h, otherwise define getcwd to call getwd.
+ (lcd): Call getcwd instead of getwd.
+ (shell): If WAIT_USES_INT, use int instead of union wait.
+ * ftp.c: Include <string.h>.
+ (L_SET, L_INCR): Define if not defined.
+
+ * ftp_var.h (index, rindex): Don't declare.
+ * main.c: Inclue <string.h>.
+ * pclose.c (getdtablesize): New function on hpux or __svr4__.
+ * radix.c (radix_encode): Cast strcmp arguments to avoid warnings.
+ * ruserpass.c: Include <string.h>. If POSIX, include <stdlib.h>
+ and don't declare malloc.
+ (MAXHOSTNAMELEN): Define if not defined.
+ (index): Don't declare.
+
+Thu Dec 15 16:13:44 1994 Ian Lance Taylor <ian@sanguine.cygnus.com>
+
+ * Initial checkin. Based on Steve Lunt's ftp program, which was
+ based on BSD code.
diff --git a/src/appl/gssftp/ftp/Makefile.in b/src/appl/gssftp/ftp/Makefile.in
new file mode 100644
index 0000000..06ee2da
--- /dev/null
+++ b/src/appl/gssftp/ftp/Makefile.in
@@ -0,0 +1,52 @@
+#
+# appl/gssftp/ftp/Makefile.in
+#
+CFLAGS = -DGSSAPI -DFTP_BUFSIZ=10240 $(CCOPTS) $(DEFS) $(LOCALINCLUDE)
+
+COMERRLIB=$(BUILDTOP)/util/et/libcom_err.a
+
+SRCS = cmds.c cmdtab.c domacro.c ftp.c getpass.c glob.c main.c pclose.c \
+ radix.c ruserpass.c secure.c
+
+
+OBJS = cmds.o cmdtab.o domacro.o ftp.o getpass.o glob.o main.o pclose.o \
+ radix.o ruserpass.o secure.o
+
+KLIB = -lgssapi_krb5 -lkrb5 -lcrypto $(COMERRLIB)
+DEPKLIB = $(TOPLIBD)/gssapi/libgssapi_krb5.a $(TOPLIBD)/libkrb5.a \
+ $(TOPLIBD)/libcrypto.a $(COMERRLIB)
+
+LOCALINCLUDE = -I$(srcdir)/..
+DEFINES = -DGSSAPI -DNOCONFIDENTIAL
+
+all:: ftp
+
+ftp: $(OBJS) $(DEPKLIB)
+ $(LD) $(LDFLAGS) $(LDARGS) -o ftp $(OBJS) $(KLIB) $(LIBS)
+
+clean::
+ $(RM) ftp
+
+depend::
+
+install::
+ $(INSTALL_PROGRAM) ftp $(DESTDIR)$(CLIENT_BINDIR)/ftp
+ $(INSTALL_DATA) $(srcdir)/ftp.M ${DESTDIR}$(CLIENT_MANDIR)/ftp.1
+
+ftp.o cmds.o main.o: $(srcdir)/../arpa/ftp.h
+ftp.o cmds.o cmdtab.o domacro.o main.o ruserpass.o: $(srcdir)/ftp_var.h
+secure.o: secure.h
+
+cmds.o: $(srcdir)/cmds.c
+cmdtab.o: $(srcdir)/cmdtab.c
+ftp.o: $(srcdir)/ftp.c
+getpass.o: $(srcdir)/getpass.c
+glob.o: $(srcdir)/glob.c
+main.o: $(srcdir)/main.c
+pclose.o: $(srcdir)/pclose.c
+ruserpass.o: $(srcdir)/ruserpass.c
+domacro.o: $(srcdir)/domacro.c
+radix.o: $(srcdir)/radix.c
+secure.o: $(srcdir)/secure.c
+
+# NOPOSTFIX
diff --git a/src/appl/gssftp/ftp/cmds.c b/src/appl/gssftp/ftp/cmds.c
new file mode 100644
index 0000000..de7e4b1
--- /dev/null
+++ b/src/appl/gssftp/ftp/cmds.c
@@ -0,0 +1,2337 @@
+/*
+ * Copyright (c) 1985, 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)cmds.c 5.26 (Berkeley) 3/5/91";
+#endif /* not lint */
+
+/*
+ * FTP User Program -- Command Routines.
+ */
+#include <sys/param.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+
+#include <arpa/ftp.h>
+
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <time.h>
+#include <netinet/in.h>
+
+#ifdef HAVE_GETCWD
+#define getwd(x) getcwd(x,MAXPATHLEN)
+#endif
+
+#include "ftp_var.h"
+#include "pathnames.h"
+
+#define sig_t my_sig_t
+#define sigtype krb5_sigtype
+typedef sigtype (*sig_t)();
+
+extern char *globerr;
+extern char **ftpglob();
+extern char *home;
+extern char *remglob();
+extern char *getenv();
+#define strerror(error) (sys_errlist[error])
+extern char *sys_errlist[];
+extern int errno;
+extern off_t restart_point;
+extern char reply_string[];
+
+char *mname;
+jmp_buf jabort;
+char *dotrans(), *domap();
+
+extern char *auth_type;
+extern int do_auth();
+
+/*
+ * `Another' gets another argument, and stores the new argc and argv.
+ * It reverts to the top level (via main.c's intr()) on EOF/error.
+ *
+ * Returns false if no new arguments have been added.
+ */
+another(pargc, pargv, prompt)
+ int *pargc;
+ char ***pargv;
+ char *prompt;
+{
+ int len = strlen(line), ret;
+ extern sig_t intr();
+
+ if (len >= sizeof(line) - 3) {
+ printf("sorry, arguments too long\n");
+ intr();
+ }
+ printf("(%s) ", prompt);
+ line[len++] = ' ';
+ if (fgets(&line[len], sizeof(line) - len, stdin) == NULL)
+ intr();
+ len += strlen(&line[len]);
+ if (len > 0 && line[len - 1] == '\n')
+ line[len - 1] = '\0';
+ makeargv();
+ ret = margc > *pargc;
+ *pargc = margc;
+ *pargv = margv;
+ return (ret);
+}
+
+/*
+ * Connect to peer server and
+ * auto-login, if possible.
+ */
+setpeer(argc, argv)
+ int argc;
+ char *argv[];
+{
+ char *host, *hookup();
+ short port;
+
+ if (connected) {
+ printf("Already connected to %s, use close first.\n",
+ hostname);
+ code = -1;
+ return;
+ }
+ if (argc < 2)
+ (void) another(&argc, &argv, "to");
+ if (argc < 2 || argc > 3) {
+ printf("usage: %s host-name [port]\n", argv[0]);
+ code = -1;
+ return;
+ }
+ port = sp->s_port;
+ if (argc > 2) {
+ port = atoi(argv[2]);
+ if (port <= 0) {
+ printf("%s: bad port number-- %s\n", argv[1], argv[2]);
+ printf ("usage: %s host-name [port]\n", argv[0]);
+ code = -1;
+ return;
+ }
+ port = htons(port);
+ }
+ host = hookup(argv[1], port);
+ if (host) {
+ int overbose;
+
+ connected = 1;
+ /*
+ * Set up defaults for FTP.
+ */
+ level = PROT_C;
+ type = TYPE_A;
+ curtype = TYPE_A;
+ form = FORM_N;
+ mode = MODE_S;
+ stru = STRU_F;
+ (void) strcpy(bytename, "8"), bytesize = 8;
+ if (autologin)
+ (void) login(argv[1]);
+
+ if (0) {
+ setpbsz(1<<20);
+ level = PROT_P;
+ if (command("PROT P") != COMPLETE)
+ fprintf(stderr, "auto PROT P setting failed\n");
+ }
+
+#ifndef unix
+#ifdef _AIX
+#define unix
+#endif
+#endif
+
+#if defined(unix) && (NBBY == 8 || defined(linux))
+/*
+ * this ifdef is to keep someone form "porting" this to an incompatible
+ * system and not checking this out. This way they have to think about it.
+ */
+ overbose = verbose;
+ if (debug == 0)
+ verbose = -1;
+ if (command("SYST") == COMPLETE && overbose) {
+ register char *cp, c;
+ cp = strchr(reply_string+4, ' ');
+ if (cp == NULL)
+ cp = strchr(reply_string+4, '\r');
+ if (cp) {
+ if (cp[-1] == '.')
+ cp--;
+ c = *cp;
+ *cp = '\0';
+ }
+
+ printf("Remote system type is %s.\n",
+ reply_string+4);
+ if (cp)
+ *cp = c;
+ }
+ if (!strncmp(reply_string, "215 UNIX Type: L8", 17)) {
+ if (proxy)
+ unix_proxy = 1;
+ else
+ unix_server = 1;
+ /*
+ * Set type to 0 (not specified by user),
+ * meaning binary by default, but don't bother
+ * telling server. We can use binary
+ * for text files unless changed by the user.
+ */
+ type = 0;
+ if (overbose)
+ printf("Using %s mode to transfer files.\n",
+ "binary");
+ } else {
+ if (proxy)
+ unix_proxy = 0;
+ else
+ unix_server = 0;
+ if (overbose &&
+ !strncmp(reply_string, "215 TOPS20", 10))
+ printf(
+"Remember to set tenex mode when transfering binary files from this machine.\n");
+ }
+ verbose = overbose;
+#endif /* unix */
+ }
+}
+
+struct levels {
+ char *p_name;
+ char *p_mode;
+ int p_level;
+} levels[] = {
+ { "clear", "C", PROT_C },
+ { "safe", "S", PROT_S },
+#ifndef NOENCRYPTION
+ { "private", "P", PROT_P },
+#endif
+ 0
+};
+
+char *
+getlevel()
+{
+ register struct levels *p;
+
+ for (p = levels; p->p_level != level; p++);
+ return(p->p_name);
+}
+
+/*
+ * Set protection level.
+ */
+setlevel(argc, argv)
+ char *argv[];
+{
+ register struct levels *p;
+ int comret;
+
+ if (argc > 2) {
+ char *sep;
+
+ printf("usage: %s [", argv[0]);
+ sep = " ";
+ for (p = levels; p->p_name; p++) {
+ printf("%s%s", sep, p->p_name);
+ if (*sep == ' ')
+ sep = " | ";
+ }
+ printf(" ]\n");
+ code = -1;
+ return;
+ }
+ if (argc < 2) {
+ printf("Using %s protection level to transfer files.\n",
+ getlevel());
+ code = 0;
+ return;
+ }
+ for (p = levels; p->p_name; p++)
+ if (strcmp(argv[1], p->p_name) == 0)
+ break;
+ if (p->p_name == 0) {
+ printf("%s: unknown protection level\n", argv[1]);
+ code = -1;
+ return;
+ }
+ if (!auth_type) {
+ if (strcmp(p->p_name, "clear"))
+ printf("Cannot set protection level to %s\n", argv[1]);
+ return;
+ }
+ /* Start with a PBSZ of 1 meg */
+ if (p->p_level != PROT_C) setpbsz(1<<20);
+ comret = command("PROT %s", p->p_mode);
+ if (comret == COMPLETE)
+ level = p->p_level;
+}
+
+char *plevel[] = {
+ "protect",
+ "",
+ 0
+};
+
+/*
+ * Set clear protection level.
+ */
+/*VARARGS*/
+setclear()
+{
+ plevel[1] = "clear";
+ setlevel(2, plevel);
+}
+
+/*
+ * Set safe protection level.
+ */
+/*VARARGS*/
+setsafe()
+{
+ plevel[1] = "safe";
+ setlevel(2, plevel);
+}
+
+#ifndef NOENCRYPTION
+/*
+ * Set private protection level.
+ */
+/*VARARGS*/
+setprivate()
+{
+ plevel[1] = "private";
+ setlevel(2, plevel);
+}
+#endif
+
+struct types {
+ char *t_name;
+ char *t_mode;
+ int t_type;
+ char *t_arg;
+} types[] = {
+ { "ascii", "A", TYPE_A, 0 },
+ { "binary", "I", TYPE_I, 0 },
+ { "image", "I", TYPE_I, 0 },
+ { "ebcdic", "E", TYPE_E, 0 },
+ { "tenex", "L", TYPE_L, bytename },
+ 0
+};
+
+char *
+gettype()
+{
+ register struct types *p;
+ int t;
+
+ t = type;
+ if (t == 0)
+ t = TYPE_I;
+ for (p = types; p->t_type != t; p++);
+ return(p->t_name);
+}
+
+/*
+ * Set transfer type.
+ */
+settype(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register struct types *p;
+ int comret;
+
+ if (argc > 2) {
+ char *sep;
+
+ printf("usage: %s [", argv[0]);
+ sep = " ";
+ for (p = types; p->t_name; p++) {
+ printf("%s%s", sep, p->t_name);
+ sep = " | ";
+ }
+ printf(" ]\n");
+ code = -1;
+ return;
+ }
+ if (argc < 2) {
+ printf("Using %s mode to transfer files.\n", gettype());
+ code = 0;
+ return;
+ }
+ for (p = types; p->t_name; p++)
+ if (strcmp(argv[1], p->t_name) == 0)
+ break;
+ if (p->t_name == 0) {
+ printf("%s: unknown mode\n", argv[1]);
+ code = -1;
+ return;
+ }
+ if ((p->t_arg != NULL) && (*(p->t_arg) != '\0'))
+ comret = command ("TYPE %s %s", p->t_mode, p->t_arg);
+ else
+ comret = command("TYPE %s", p->t_mode);
+ if (comret == COMPLETE)
+ curtype = type = p->t_type;
+}
+
+/*
+ * Internal form of settype; changes current type in use with server
+ * without changing our notion of the type for data transfers.
+ * Used to change to and from ascii for listings.
+ */
+changetype(newtype, show)
+ int newtype, show;
+{
+ register struct types *p;
+ int comret, oldverbose = verbose;
+
+ if (newtype == 0)
+ newtype = TYPE_I;
+ if (newtype == curtype)
+ return;
+ if (debug == 0 && show == 0)
+ verbose = 0;
+ for (p = types; p->t_name; p++)
+ if (newtype == p->t_type)
+ break;
+ if (p->t_name == 0) {
+ printf("ftp: internal error: unknown type %d\n", newtype);
+ return;
+ }
+ if (newtype == TYPE_L && bytename[0] != '\0')
+ comret = command("TYPE %s %s", p->t_mode, bytename);
+ else
+ comret = command("TYPE %s", p->t_mode);
+ if (comret == COMPLETE)
+ curtype = newtype;
+ verbose = oldverbose;
+}
+
+char *stype[] = {
+ "type",
+ "",
+ 0
+};
+
+/*
+ * Set binary transfer type.
+ */
+/*VARARGS*/
+setbinary()
+{
+ stype[1] = "binary";
+ settype(2, stype);
+}
+
+/*
+ * Set ascii transfer type.
+ */
+/*VARARGS*/
+setascii()
+{
+ stype[1] = "ascii";
+ settype(2, stype);
+}
+
+/*
+ * Set tenex transfer type.
+ */
+/*VARARGS*/
+settenex()
+{
+ stype[1] = "tenex";
+ settype(2, stype);
+}
+
+char *
+getmode()
+{
+ return("stream");
+}
+
+/*
+ * Set file transfer mode.
+ */
+/*ARGSUSED*/
+setmode(argc, argv)
+ int argc;
+ char *argv[];
+{
+
+ printf("We only support %s mode, sorry.\n", getmode());
+ code = -1;
+}
+
+char *
+getform()
+{
+ return("non-print");
+}
+
+/*
+ * Set file transfer format.
+ */
+/*ARGSUSED*/
+setform(argc, argv)
+ int argc;
+ char *argv[];
+{
+
+ printf("We only support %s format, sorry.\n", getform());
+ code = -1;
+}
+
+char *
+getstruct()
+{
+ return("file");
+}
+
+/*
+ * Set file transfer structure.
+ */
+/*ARGSUSED*/
+setstruct(argc, argv)
+ int argc;
+ char *argv[];
+{
+
+ printf("We only support %s structure, sorry.\n", getstruct());
+ code = -1;
+}
+
+/*
+ * Send a single file.
+ */
+put(argc, argv)
+ int argc;
+ char *argv[];
+{
+ char *cmd;
+ int loc = 0;
+ char *oldargv1, *oldargv2;
+
+ if (argc == 2) {
+ argc++;
+ argv[2] = argv[1];
+ loc++;
+ }
+ if (argc < 2 && !another(&argc, &argv, "local-file"))
+ goto usage;
+ if (argc < 3 && !another(&argc, &argv, "remote-file")) {
+usage:
+ printf("usage: %s local-file remote-file\n", argv[0]);
+ code = -1;
+ return;
+ }
+ oldargv1 = argv[1];
+ oldargv2 = argv[2];
+ if (!globulize(&argv[1])) {
+ code = -1;
+ return;
+ }
+ /*
+ * If "globulize" modifies argv[1], and argv[2] is a copy of
+ * the old argv[1], make it a copy of the new argv[1].
+ */
+ if (argv[1] != oldargv1 && argv[2] == oldargv1) {
+ argv[2] = argv[1];
+ }
+ cmd = (argv[0][0] == 'a') ? "APPE" : ((sunique) ? "STOU" : "STOR");
+ if (loc && ntflag) {
+ argv[2] = dotrans(argv[2]);
+ }
+ if (loc && mapflag) {
+ argv[2] = domap(argv[2]);
+ }
+ sendrequest(cmd, argv[1], argv[2],
+ argv[1] != oldargv1 || argv[2] != oldargv2);
+}
+
+/*
+ * Send multiple files.
+ */
+mput(argc, argv)
+ int argc;
+ char **argv;
+{
+ extern jmp_buf jabort;
+ register int i;
+ sig_t oldintr;
+ int ointer;
+ char *tp;
+ sigtype mabort();
+
+ if (argc < 2 && !another(&argc, &argv, "local-files")) {
+ printf("usage: %s local-files\n", argv[0]);
+ code = -1;
+ return;
+ }
+ mname = argv[0];
+ mflag = 1;
+ oldintr = signal(SIGINT, mabort);
+ (void) setjmp(jabort);
+ if (proxy) {
+ char *cp, *tp2, tmpbuf[MAXPATHLEN];
+
+ while ((cp = remglob(argv,0)) != NULL) {
+ if (*cp == 0) {
+ mflag = 0;
+ continue;
+ }
+ if (mflag && confirm(argv[0], cp)) {
+ tp = cp;
+ if (mcase) {
+ while (*tp && !islower(*tp)) {
+ tp++;
+ }
+ if (!*tp) {
+ tp = cp;
+ tp2 = tmpbuf;
+ while ((*tp2 = *tp) != 0) {
+ if (isupper(*tp2)) {
+ *tp2 = 'a' + *tp2 - 'A';
+ }
+ tp++;
+ tp2++;
+ }
+ }
+ tp = tmpbuf;
+ }
+ if (ntflag) {
+ tp = dotrans(tp);
+ }
+ if (mapflag) {
+ tp = domap(tp);
+ }
+ sendrequest((sunique) ? "STOU" : "STOR",
+ cp, tp, cp != tp || !interactive);
+ if (!mflag && fromatty) {
+ ointer = interactive;
+ interactive = 1;
+ if (confirm("Continue with","mput")) {
+ mflag++;
+ }
+ interactive = ointer;
+ }
+ }
+ }
+ (void) signal(SIGINT, oldintr);
+ mflag = 0;
+ return;
+ }
+ for (i = 1; i < argc; i++) {
+ register char **cpp, **gargs;
+
+ if (!doglob) {
+ if (mflag && confirm(argv[0], argv[i])) {
+ tp = (ntflag) ? dotrans(argv[i]) : argv[i];
+ tp = (mapflag) ? domap(tp) : tp;
+ sendrequest((sunique) ? "STOU" : "STOR",
+ argv[i], tp, tp != argv[i] || !interactive);
+ if (!mflag && fromatty) {
+ ointer = interactive;
+ interactive = 1;
+ if (confirm("Continue with","mput")) {
+ mflag++;
+ }
+ interactive = ointer;
+ }
+ }
+ continue;
+ }
+ gargs = ftpglob(argv[i]);
+ if (globerr != NULL) {
+ printf("%s\n", globerr);
+ if (gargs) {
+ blkfree(gargs);
+ free((char *)gargs);
+ }
+ continue;
+ }
+ for (cpp = gargs; cpp && *cpp != NULL; cpp++) {
+ if (mflag && confirm(argv[0], *cpp)) {
+ tp = (ntflag) ? dotrans(*cpp) : *cpp;
+ tp = (mapflag) ? domap(tp) : tp;
+ sendrequest((sunique) ? "STOU" : "STOR",
+ *cpp, tp, *cpp != tp || !interactive);
+ if (!mflag && fromatty) {
+ ointer = interactive;
+ interactive = 1;
+ if (confirm("Continue with","mput")) {
+ mflag++;
+ }
+ interactive = ointer;
+ }
+ }
+ }
+ if (gargs != NULL) {
+ blkfree(gargs);
+ free((char *)gargs);
+ }
+ }
+ (void) signal(SIGINT, oldintr);
+ mflag = 0;
+}
+
+reget(argc, argv)
+ int argc;
+ char *argv[];
+{
+ (void) getit(argc, argv, 1, "r+w");
+}
+
+get(argc, argv)
+ int argc;
+ char *argv[];
+{
+ (void) getit(argc, argv, 0, restart_point ? "r+w" : "w" );
+}
+
+/*
+ * Receive one file.
+ */
+getit(argc, argv, restartit, mode)
+ int argc;
+ char *argv[];
+ char *mode;
+{
+ int loc = 0;
+ char *oldargv1, *oldargv2;
+
+ if (argc == 2) {
+ argc++;
+ argv[2] = argv[1];
+ loc++;
+ }
+ if (argc < 2 && !another(&argc, &argv, "remote-file"))
+ goto usage;
+ if (argc < 3 && !another(&argc, &argv, "local-file")) {
+usage:
+ printf("usage: %s remote-file [ local-file ]\n", argv[0]);
+ code = -1;
+ return (0);
+ }
+ oldargv1 = argv[1];
+ oldargv2 = argv[2];
+ if (!globulize(&argv[2])) {
+ code = -1;
+ return (0);
+ }
+ if (loc && mcase) {
+ char *tp = argv[1], *tp2, tmpbuf[MAXPATHLEN];
+
+ while (*tp && !islower(*tp)) {
+ tp++;
+ }
+ if (!*tp) {
+ tp = argv[2];
+ tp2 = tmpbuf;
+ while ((*tp2 = *tp) != 0) {
+ if (isupper(*tp2)) {
+ *tp2 = 'a' + *tp2 - 'A';
+ }
+ tp++;
+ tp2++;
+ }
+ argv[2] = tmpbuf;
+ }
+ }
+ if (loc && ntflag)
+ argv[2] = dotrans(argv[2]);
+ if (loc && mapflag)
+ argv[2] = domap(argv[2]);
+ if (restartit) {
+ struct stat stbuf;
+ int ret;
+
+ ret = stat(argv[2], &stbuf);
+ if (restartit == 1) {
+ if (ret < 0) {
+ fprintf(stderr, "local: %s: %s\n", argv[2],
+ strerror(errno));
+ return (0);
+ }
+ restart_point = stbuf.st_size;
+ } else {
+ if (ret == 0) {
+ int overbose;
+
+ overbose = verbose;
+ if (debug == 0)
+ verbose = -1;
+ if (command("MDTM %s", argv[1]) == COMPLETE) {
+ int yy, mo, day, hour, min, sec;
+ struct tm *tm;
+ verbose = overbose;
+ sscanf(reply_string,
+ "%*s %04d%02d%02d%02d%02d%02d",
+ &yy, &mo, &day, &hour, &min, &sec);
+ tm = gmtime(&stbuf.st_mtime);
+ tm->tm_mon++;
+ if (tm->tm_year > yy%100)
+ return (1);
+ else if (tm->tm_year == yy%100) {
+ if (tm->tm_mon > mo)
+ return (1);
+ } else if (tm->tm_mon == mo) {
+ if (tm->tm_mday > day)
+ return (1);
+ } else if (tm->tm_mday == day) {
+ if (tm->tm_hour > hour)
+ return (1);
+ } else if (tm->tm_hour == hour) {
+ if (tm->tm_min > min)
+ return (1);
+ } else if (tm->tm_min == min) {
+ if (tm->tm_sec > sec)
+ return (1);
+ }
+ } else {
+ printf("%s\n", reply_string);
+ verbose = overbose;
+ return (0);
+ }
+ }
+ }
+ }
+
+ recvrequest("RETR", argv[2], argv[1], mode,
+ argv[1] != oldargv1 || argv[2] != oldargv2);
+ restart_point = 0;
+ return (0);
+}
+
+sigtype
+mabort(sig)
+ int sig;
+{
+ int ointer;
+ extern jmp_buf jabort;
+
+ printf("\n");
+ (void) fflush(stdout);
+ if (mflag && fromatty) {
+ ointer = interactive;
+ interactive = 1;
+ if (confirm("Continue with", mname)) {
+ interactive = ointer;
+ longjmp(jabort,0);
+ }
+ interactive = ointer;
+ }
+ mflag = 0;
+ longjmp(jabort,0);
+}
+
+/*
+ * Get multiple files.
+ */
+mget(argc, argv)
+ int argc;
+ char **argv;
+{
+ extern jmp_buf jabort;
+ sig_t oldintr;
+ int ointer;
+ char *cp, *tp, *tp2, tmpbuf[MAXPATHLEN];
+ sigtype mabort();
+
+ if (argc < 2 && !another(&argc, &argv, "remote-files")) {
+ printf("usage: %s remote-files\n", argv[0]);
+ code = -1;
+ return;
+ }
+ mname = argv[0];
+ mflag = 1;
+ oldintr = signal(SIGINT,mabort);
+ (void) setjmp(jabort);
+ while ((cp = remglob(argv,proxy)) != NULL) {
+ if (*cp == '\0') {
+ mflag = 0;
+ continue;
+ }
+ if (mflag && confirm(argv[0], cp)) {
+ tp = cp;
+ if (mcase) {
+ while (*tp && !islower(*tp)) {
+ tp++;
+ }
+ if (!*tp) {
+ tp = cp;
+ tp2 = tmpbuf;
+ while ((*tp2 = *tp) != 0) {
+ if (isupper(*tp2)) {
+ *tp2 = 'a' + *tp2 - 'A';
+ }
+ tp++;
+ tp2++;
+ }
+ }
+ tp = tmpbuf;
+ }
+ if (ntflag) {
+ tp = dotrans(tp);
+ }
+ if (mapflag) {
+ tp = domap(tp);
+ }
+ recvrequest("RETR", tp, cp, "w",
+ tp != cp || !interactive);
+ if (!mflag && fromatty) {
+ ointer = interactive;
+ interactive = 1;
+ if (confirm("Continue with","mget")) {
+ mflag++;
+ }
+ interactive = ointer;
+ }
+ }
+ }
+ (void) signal(SIGINT,oldintr);
+ mflag = 0;
+}
+
+char *
+remglob(argv,doswitch)
+ char *argv[];
+ int doswitch;
+{
+ char temp[16];
+ static char buf[MAXPATHLEN];
+ static FILE *ftemp = NULL;
+ static char **args;
+ int oldverbose, oldhash;
+ char *cp, *mode;
+
+ if (!mflag) {
+ if (!doglob) {
+ args = NULL;
+ }
+ else {
+ if (ftemp) {
+ (void) fclose(ftemp);
+ ftemp = NULL;
+ }
+ }
+ return(NULL);
+ }
+ if (!doglob) {
+ if (args == NULL)
+ args = argv;
+ if ((cp = *++args) == NULL)
+ args = NULL;
+ return (cp);
+ }
+ if (ftemp == NULL) {
+ (void) strcpy(temp, _PATH_TMP);
+ (void) mktemp(temp);
+ oldverbose = verbose, verbose = 0;
+ oldhash = hash, hash = 0;
+ if (doswitch) {
+ pswitch(!proxy);
+ }
+ for (mode = "w"; *++argv != NULL; mode = "a")
+ recvrequest ("NLST", temp, *argv, mode, 0);
+ if (doswitch) {
+ pswitch(!proxy);
+ }
+ verbose = oldverbose; hash = oldhash;
+ ftemp = fopen(temp, "r");
+ (void) unlink(temp);
+ if (ftemp == NULL) {
+ printf("can't find list of remote files, oops\n");
+ return (NULL);
+ }
+ }
+ if (fgets(buf, sizeof (buf), ftemp) == NULL) {
+ (void) fclose(ftemp), ftemp = NULL;
+ return (NULL);
+ }
+ if ((cp = strchr(buf, '\n')) != NULL)
+ *cp = '\0';
+ return (buf);
+}
+
+char *
+onoff(bool)
+ int bool;
+{
+
+ return (bool ? "on" : "off");
+}
+
+cstatus()
+{
+ if (!connected) {
+ printf(proxy ? "No proxy connection.\n" : "Not connected.\n");
+ return;
+ }
+ printf("Connected %sto %s.\n",
+ proxy ? "for proxy commands " : "", hostname);
+ if (auth_type) printf("Authentication type: %s\n", auth_type);
+ printf("Protection Level: %s\n", getlevel());
+ printf("Passive mode %s\n", onoff(passivemode));
+ printf("Mode: %s; Type: %s; Form: %s; Structure: %s\n",
+ getmode(), gettype(), getform(), getstruct());
+ printf("Store unique: %s; Receive unique: %s\n", onoff(sunique),
+ onoff(runique));
+ printf("Case: %s; CR stripping: %s\n",onoff(mcase),onoff(crflag));
+ if (ntflag) {
+ printf("Ntrans: (in) %s (out) %s\n", ntin,ntout);
+ }
+ else {
+ printf("Ntrans: off\n");
+ }
+ if (mapflag) {
+ printf("Nmap: (in) %s (out) %s\n", mapin, mapout);
+ }
+ else {
+ printf("Nmap: off\n");
+ }
+}
+
+/*
+ * Show status.
+ */
+/*ARGSUSED*/
+status(argc, argv)
+ char *argv[];
+{
+ int i;
+
+ cstatus();
+ if (!proxy) {
+ pswitch(1);
+ if (connected) putchar('\n');
+ cstatus(argc,argv);
+ if (connected) putchar('\n');
+ pswitch(0);
+ }
+ printf("Hash mark printing: %s; Use of PORT cmds: %s\n",
+ onoff(hash), onoff(sendport));
+ printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n",
+ onoff(verbose), onoff(bell), onoff(interactive),
+ onoff(doglob));
+ if (macnum > 0) {
+ printf("Macros:\n");
+ for (i=0; i<macnum; i++) {
+ printf("\t%s\n",macros[i].mac_name);
+ }
+ }
+ code = 0;
+}
+
+/*
+ * Set beep on cmd completed mode.
+ */
+/*VARARGS*/
+setbell()
+{
+
+ bell = !bell;
+ printf("Bell mode %s.\n", onoff(bell));
+ code = bell;
+}
+
+/*
+ * Turn on packet tracing.
+ */
+/*VARARGS*/
+settrace()
+{
+
+ trace = !trace;
+ printf("Packet tracing %s.\n", onoff(trace));
+ code = trace;
+}
+
+/*
+ * Toggle hash mark printing during transfers.
+ */
+/*VARARGS*/
+sethash()
+{
+
+ hash = !hash;
+ printf("Hash mark printing %s", onoff(hash));
+ code = hash;
+ if (hash)
+ printf(" (%d bytes/hash mark)", 1024);
+ printf(".\n");
+}
+
+/*
+ * Turn on printing of server echo's.
+ */
+/*VARARGS*/
+setverbose()
+{
+
+ verbose = !verbose;
+ printf("Verbose mode %s.\n", onoff(verbose));
+ code = verbose;
+}
+
+/*
+ * Toggle PORT cmd use before each data connection.
+ */
+/*VARARGS*/
+setport()
+{
+
+ sendport = !sendport;
+ printf("Use of PORT cmds %s.\n", onoff(sendport));
+ code = sendport;
+}
+
+/*
+ * Turn on interactive prompting
+ * during mget, mput, and mdelete.
+ */
+/*VARARGS*/
+setprompt()
+{
+
+ interactive = !interactive;
+ printf("Interactive mode %s.\n", onoff(interactive));
+ code = interactive;
+}
+
+/*
+ * Toggle metacharacter interpretation
+ * on local file names.
+ */
+/*VARARGS*/
+setglob()
+{
+
+ doglob = !doglob;
+ printf("Globbing %s.\n", onoff(doglob));
+ code = doglob;
+}
+
+/*
+ * Set debugging mode on/off and/or
+ * set level of debugging.
+ */
+/*VARARGS*/
+setdebug(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int val;
+
+ if (argc > 1) {
+ val = atoi(argv[1]);
+ if (val < 0) {
+ printf("%s: bad debugging value.\n", argv[1]);
+ code = -1;
+ return;
+ }
+ } else
+ val = !debug;
+ debug = val;
+ if (debug)
+ options |= SO_DEBUG;
+ else
+ options &= ~SO_DEBUG;
+ printf("Debugging %s (debug=%d).\n", onoff(debug), debug);
+ code = debug > 0;
+}
+
+/*
+ * Set current working directory
+ * on remote machine.
+ */
+cd(argc, argv)
+ int argc;
+ char *argv[];
+{
+
+ if (argc < 2 && !another(&argc, &argv, "remote-directory")) {
+ printf("usage: %s remote-directory\n", argv[0]);
+ code = -1;
+ return;
+ }
+ if (command("CWD %s", argv[1]) == ERROR && code == 500) {
+ if (verbose)
+ printf("CWD command not recognized, trying XCWD\n");
+ (void) command("XCWD %s", argv[1]);
+ }
+}
+
+/*
+ * Set current working directory
+ * on local machine.
+ */
+lcd(argc, argv)
+ int argc;
+ char *argv[];
+{
+ char buf[MAXPATHLEN];
+
+ if (argc < 2)
+ argc++, argv[1] = home;
+ if (argc != 2) {
+ printf("usage: %s local-directory\n", argv[0]);
+ code = -1;
+ return;
+ }
+ if (!globulize(&argv[1])) {
+ code = -1;
+ return;
+ }
+ if (chdir(argv[1]) < 0) {
+ fprintf(stderr, "local: %s: %s\n", argv[1], strerror(errno));
+ code = -1;
+ return;
+ }
+ printf("Local directory now %s\n", getcwd(buf, sizeof buf));
+ code = 0;
+}
+
+/*
+ * Delete a single file.
+ */
+delete(argc, argv)
+ int argc;
+ char *argv[];
+{
+
+ if (argc < 2 && !another(&argc, &argv, "remote-file")) {
+ printf("usage: %s remote-file\n", argv[0]);
+ code = -1;
+ return;
+ }
+ (void) command("DELE %s", argv[1]);
+}
+
+/*
+ * Delete multiple files.
+ */
+mdelete(argc, argv)
+ int argc;
+ char **argv;
+{
+ extern jmp_buf jabort;
+ sig_t oldintr;
+ int ointer;
+ char *cp;
+ sigtype mabort();
+
+ if (argc < 2 && !another(&argc, &argv, "remote-files")) {
+ printf("usage: %s remote-files\n", argv[0]);
+ code = -1;
+ return;
+ }
+ mname = argv[0];
+ mflag = 1;
+ oldintr = signal(SIGINT, mabort);
+ (void) setjmp(jabort);
+ while ((cp = remglob(argv,0)) != NULL) {
+ if (*cp == '\0') {
+ mflag = 0;
+ continue;
+ }
+ if (mflag && confirm(argv[0], cp)) {
+ (void) command("DELE %s", cp);
+ if (!mflag && fromatty) {
+ ointer = interactive;
+ interactive = 1;
+ if (confirm("Continue with", "mdelete")) {
+ mflag++;
+ }
+ interactive = ointer;
+ }
+ }
+ }
+ (void) signal(SIGINT, oldintr);
+ mflag = 0;
+}
+
+/*
+ * Rename a remote file.
+ */
+renamefile(argc, argv)
+ int argc;
+ char *argv[];
+{
+
+ if (argc < 2 && !another(&argc, &argv, "from-name"))
+ goto usage;
+ if (argc < 3 && !another(&argc, &argv, "to-name")) {
+usage:
+ printf("%s from-name to-name\n", argv[0]);
+ code = -1;
+ return;
+ }
+ if (command("RNFR %s", argv[1]) == CONTINUE)
+ (void) command("RNTO %s", argv[2]);
+}
+
+/*
+ * Get a directory listing
+ * of remote files.
+ */
+ls(argc, argv)
+ int argc;
+ char *argv[];
+{
+ char *cmd;
+
+ if (argc < 2)
+ argc++, argv[1] = NULL;
+ if (argc < 3)
+ argc++, argv[2] = "-";
+ if (argc > 3) {
+ printf("usage: %s remote-directory local-file\n", argv[0]);
+ code = -1;
+ return;
+ }
+ cmd = argv[0][0] == 'n' ? "NLST" : "LIST";
+ if (strcmp(argv[2], "-") && !globulize(&argv[2])) {
+ code = -1;
+ return;
+ }
+ if (strcmp(argv[2], "-") && *argv[2] != '|')
+ if (!globulize(&argv[2]) || !confirm("output to local-file:", argv[2])) {
+ code = -1;
+ return;
+ }
+ recvrequest(cmd, argv[2], argv[1], "w", 0);
+}
+
+/*
+ * Get a directory listing
+ * of multiple remote files.
+ */
+mls(argc, argv)
+ int argc;
+ char **argv;
+{
+ extern jmp_buf jabort;
+ sig_t oldintr;
+ int ointer, i;
+ char *cmd, mode[1], *dest;
+ sigtype mabort();
+
+ if (argc < 2 && !another(&argc, &argv, "remote-files"))
+ goto usage;
+ if (argc < 3 && !another(&argc, &argv, "local-file")) {
+usage:
+ printf("usage: %s remote-files local-file\n", argv[0]);
+ code = -1;
+ return;
+ }
+ dest = argv[argc - 1];
+ argv[argc - 1] = NULL;
+ if (strcmp(dest, "-") && *dest != '|')
+ if (!globulize(&dest) ||
+ !confirm("output to local-file:", dest)) {
+ code = -1;
+ return;
+ }
+ cmd = argv[0][1] == 'l' ? "NLST" : "LIST";
+ mname = argv[0];
+ mflag = 1;
+ oldintr = signal(SIGINT, mabort);
+ (void) setjmp(jabort);
+ for (i = 1; mflag && i < argc-1; ++i) {
+ *mode = (i == 1) ? 'w' : 'a';
+ recvrequest(cmd, dest, argv[i], mode, 0);
+ if (!mflag && fromatty) {
+ ointer = interactive;
+ interactive = 1;
+ if (confirm("Continue with", argv[0])) {
+ mflag ++;
+ }
+ interactive = ointer;
+ }
+ }
+ (void) signal(SIGINT, oldintr);
+ mflag = 0;
+}
+
+/*
+ * Do a shell escape
+ */
+/*ARGSUSED*/
+shell(argc, argv)
+ int argc;
+ char **argv;
+{
+ int pid;
+ sig_t old1, old2;
+ char shellnam[40], *shell, *namep;
+#ifdef WAIT_USES_INT
+ int status;
+#else
+ union wait status;
+#endif
+
+ old1 = signal (SIGINT, SIG_IGN);
+ old2 = signal (SIGQUIT, SIG_IGN);
+ if ((pid = fork()) == 0) {
+ for (pid = 3; pid < 20; pid++)
+ (void) close(pid);
+ (void) signal(SIGINT, SIG_DFL);
+ (void) signal(SIGQUIT, SIG_DFL);
+ shell = getenv("SHELL");
+ if (shell == NULL)
+ shell = "/bin/sh";
+ namep = strrchr(shell,'/');
+ if (namep == NULL)
+ namep = shell;
+ (void) strcpy(shellnam,"-");
+ (void) strcat(shellnam, ++namep);
+ if (strcmp(namep, "sh") != 0)
+ shellnam[0] = '+';
+ if (debug) {
+ printf ("%s\n", shell);
+ (void) fflush (stdout);
+ }
+ if (argc > 1) {
+ execl(shell,shellnam,"-c",altarg,(char *)0);
+ }
+ else {
+ execl(shell,shellnam,(char *)0);
+ }
+ perror(shell);
+ code = -1;
+ exit(1);
+ }
+ if (pid > 0)
+ while (wait(&status) != pid)
+ ;
+ (void) signal(SIGINT, old1);
+ (void) signal(SIGQUIT, old2);
+ if (pid == -1) {
+ perror("Try again later");
+ code = -1;
+ }
+ else {
+ code = 0;
+ }
+ return (0);
+}
+
+/*
+ * Send new user information (re-login)
+ */
+user(argc, argv)
+ int argc;
+ char **argv;
+{
+ char acct[80], *mygetpass();
+ int n, aflag = 0;
+
+ if (argc < 2)
+ (void) another(&argc, &argv, "username");
+ if (argc < 2 || argc > 4) {
+ printf("usage: %s username [password] [account]\n", argv[0]);
+ code = -1;
+ return (0);
+ }
+ n = command("USER %s", argv[1]);
+ if (n == COMPLETE)
+ n = command("PASS dummy");
+ else if (n == CONTINUE) {
+#ifndef NOENCRYPTION
+ int oldlevel;
+#endif
+ if (argc < 3 )
+ argv[2] = mygetpass("Password: "), argc++;
+#ifndef NOENCRYPTION
+ if ((oldlevel = level) == PROT_S) level = PROT_P;
+#endif
+ n = command("PASS %s", argv[2]);
+#ifndef NOENCRYPTION
+ /* level may have changed */
+ if (level == PROT_P) level = oldlevel;
+#endif
+ }
+ if (n == CONTINUE) {
+ if (argc < 4) {
+ printf("Account: "); (void) fflush(stdout);
+ (void) fgets(acct, sizeof(acct) - 1, stdin);
+ acct[strlen(acct) - 1] = '\0';
+ argv[3] = acct; argc++;
+ }
+ n = command("ACCT %s", argv[3]);
+ aflag++;
+ }
+ if (n != COMPLETE) {
+ fprintf(stdout, "Login failed.\n");
+ return (0);
+ }
+ if (!aflag && argc == 4) {
+ (void) command("ACCT %s", argv[3]);
+ }
+ return (1);
+}
+
+/*
+ * Print working directory.
+ */
+/*VARARGS*/
+pwd()
+{
+ int oldverbose = verbose;
+
+ /*
+ * If we aren't verbose, this doesn't do anything!
+ */
+ verbose = 1;
+ if (command("PWD") == ERROR && code == 500) {
+ printf("PWD command not recognized, trying XPWD\n");
+ (void) command("XPWD");
+ }
+ verbose = oldverbose;
+}
+
+/*
+ * Make a directory.
+ */
+makedir(argc, argv)
+ int argc;
+ char *argv[];
+{
+
+ if (argc < 2 && !another(&argc, &argv, "directory-name")) {
+ printf("usage: %s directory-name\n", argv[0]);
+ code = -1;
+ return;
+ }
+ if (command("MKD %s", argv[1]) == ERROR && code == 500) {
+ if (verbose)
+ printf("MKD command not recognized, trying XMKD\n");
+ (void) command("XMKD %s", argv[1]);
+ }
+}
+
+/*
+ * Remove a directory.
+ */
+removedir(argc, argv)
+ int argc;
+ char *argv[];
+{
+
+ if (argc < 2 && !another(&argc, &argv, "directory-name")) {
+ printf("usage: %s directory-name\n", argv[0]);
+ code = -1;
+ return;
+ }
+ if (command("RMD %s", argv[1]) == ERROR && code == 500) {
+ if (verbose)
+ printf("RMD command not recognized, trying XRMD\n");
+ (void) command("XRMD %s", argv[1]);
+ }
+}
+
+/*
+ * Send a line, verbatim, to the remote machine.
+ */
+quote(argc, argv)
+ int argc;
+ char *argv[];
+{
+
+ if (argc < 2 && !another(&argc, &argv, "command line to send")) {
+ printf("usage: %s line-to-send\n", argv[0]);
+ code = -1;
+ return;
+ }
+ quote1("", argc, argv);
+}
+
+/*
+ * Send a SITE command to the remote machine. The line
+ * is sent verbatim to the remote machine, except that the
+ * word "SITE" is added at the front.
+ */
+site(argc, argv)
+ int argc;
+ char *argv[];
+{
+
+ if (argc < 2 && !another(&argc, &argv, "arguments to SITE command")) {
+ printf("usage: %s line-to-send\n", argv[0]);
+ code = -1;
+ return;
+ }
+ quote1("SITE ", argc, argv);
+}
+
+/*
+ * Turn argv[1..argc) into a space-separated string, then prepend initial text.
+ * Send the result as a one-line command and get response.
+ */
+quote1(initial, argc, argv)
+ char *initial;
+ int argc;
+ char **argv;
+{
+ register int i, len;
+ char buf[FTP_BUFSIZ]; /* must be >= sizeof(line) */
+
+ (void) strcpy(buf, initial);
+ if (argc > 1) {
+ len = strlen(buf);
+ len += strlen(strcpy(&buf[len], argv[1]));
+ for (i = 2; i < argc; i++) {
+ buf[len++] = ' ';
+ len += strlen(strcpy(&buf[len], argv[i]));
+ }
+ }
+ if (command(buf) == PRELIM) {
+ while (getreply(0) == PRELIM);
+ }
+}
+
+do_chmod(argc, argv)
+ int argc;
+ char *argv[];
+{
+
+ if (argc < 2 && !another(&argc, &argv, "mode"))
+ goto usage;
+ if (argc < 3 && !another(&argc, &argv, "file-name")) {
+usage:
+ printf("usage: %s mode file-name\n", argv[0]);
+ code = -1;
+ return;
+ }
+ (void) command("SITE CHMOD %s %s", argv[1], argv[2]);
+}
+
+do_umask(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int oldverbose = verbose;
+
+ verbose = 1;
+ (void) command(argc == 1 ? "SITE UMASK" : "SITE UMASK %s", argv[1]);
+ verbose = oldverbose;
+}
+
+siteidle(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int oldverbose = verbose;
+
+ verbose = 1;
+ (void) command(argc == 1 ? "SITE IDLE" : "SITE IDLE %s", argv[1]);
+ verbose = oldverbose;
+}
+
+/*
+ * Ask the other side for help.
+ */
+rmthelp(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int oldverbose = verbose;
+
+ verbose = 1;
+ (void) command(argc == 1 ? "HELP" : "HELP %s", argv[1]);
+ verbose = oldverbose;
+}
+
+/*
+ * Terminate session and exit.
+ */
+/*VARARGS*/
+quit()
+{
+
+ if (connected)
+ disconnect();
+ pswitch(1);
+ if (connected) {
+ disconnect();
+ }
+ exit(0);
+}
+
+/*
+ * Terminate session, but don't exit.
+ */
+disconnect()
+{
+ extern FILE *cout;
+ extern int data;
+
+ if (!connected)
+ return;
+ (void) command("QUIT");
+ if (cout) {
+ (void) fclose(cout);
+ }
+ cout = NULL;
+ connected = 0;
+ data = -1;
+ if (!proxy) {
+ macnum = 0;
+ }
+ auth_type = NULL;
+ level = PROT_C;
+}
+
+confirm(cmd, file)
+ char *cmd, *file;
+{
+ char line[FTP_BUFSIZ];
+
+ if (!interactive)
+ return (1);
+ printf("%s %s? ", cmd, file);
+ (void) fflush(stdout);
+ if (fgets(line, sizeof line, stdin) == NULL)
+ return (0);
+ return (*line != 'n' && *line != 'N');
+}
+
+fatal(msg)
+ char *msg;
+{
+
+ fprintf(stderr, "ftp: %s\n", msg);
+ exit(1);
+}
+
+/*
+ * Glob a local file name specification with
+ * the expectation of a single return value.
+ * Can't control multiple values being expanded
+ * from the expression, we return only the first.
+ */
+globulize(cpp)
+ char **cpp;
+{
+ char **globbed;
+
+ if (!doglob)
+ return (1);
+ globbed = ftpglob(*cpp);
+ if (globerr != NULL) {
+ printf("%s: %s\n", *cpp, globerr);
+ if (globbed) {
+ blkfree(globbed);
+ free((char *)globbed);
+ }
+ return (0);
+ }
+ if (globbed) {
+ *cpp = *globbed++;
+ /* don't waste too much memory */
+ if (*globbed) {
+ blkfree(globbed);
+ free((char *)globbed);
+ }
+ }
+ return (1);
+}
+
+account(argc,argv)
+ int argc;
+ char **argv;
+{
+ char acct[50], *mygetpass(), *ap;
+
+ if (argc > 1) {
+ ++argv;
+ --argc;
+ (void) strncpy(acct,*argv,49);
+ acct[49] = '\0';
+ while (argc > 1) {
+ --argc;
+ ++argv;
+ (void) strncat(acct,*argv, 49-strlen(acct));
+ }
+ ap = acct;
+ }
+ else {
+ ap = mygetpass("Account:");
+ }
+ (void) command("ACCT %s", ap);
+}
+
+jmp_buf abortprox;
+
+sigtype
+proxabort(sig)
+ int sig;
+{
+ extern int proxy;
+
+ if (!proxy) {
+ pswitch(1);
+ }
+ if (connected) {
+ proxflag = 1;
+ }
+ else {
+ proxflag = 0;
+ }
+ pswitch(0);
+ longjmp(abortprox,1);
+}
+
+doproxy(argc,argv)
+ int argc;
+ char *argv[];
+{
+ extern struct cmd cmdtab[];
+ extern jmp_buf abortprox;
+ register struct cmd *c;
+ struct cmd *getcmd();
+ sig_t oldintr;
+ sigtype proxabort();
+
+ if (argc < 2 && !another(&argc, &argv, "command")) {
+ printf("usage: %s command\n", argv[0]);
+ code = -1;
+ return;
+ }
+ c = getcmd(argv[1]);
+ if (c == (struct cmd *) -1) {
+ printf("?Ambiguous command\n");
+ (void) fflush(stdout);
+ code = -1;
+ return;
+ }
+ if (c == 0) {
+ printf("?Invalid command\n");
+ (void) fflush(stdout);
+ code = -1;
+ return;
+ }
+ if (!c->c_proxy) {
+ printf("?Invalid proxy command\n");
+ (void) fflush(stdout);
+ code = -1;
+ return;
+ }
+ if (setjmp(abortprox)) {
+ code = -1;
+ return;
+ }
+ oldintr = signal(SIGINT, proxabort);
+ pswitch(1);
+ if (c->c_conn && !connected) {
+ printf("Not connected\n");
+ (void) fflush(stdout);
+ pswitch(0);
+ (void) signal(SIGINT, oldintr);
+ code = -1;
+ return;
+ }
+ (*c->c_handler)(argc-1, argv+1);
+ if (connected) {
+ proxflag = 1;
+ }
+ else {
+ proxflag = 0;
+ }
+ pswitch(0);
+ (void) signal(SIGINT, oldintr);
+}
+
+setcase()
+{
+ mcase = !mcase;
+ printf("Case mapping %s.\n", onoff(mcase));
+ code = mcase;
+}
+
+setcr()
+{
+ crflag = !crflag;
+ printf("Carriage Return stripping %s.\n", onoff(crflag));
+ code = crflag;
+}
+
+setntrans(argc,argv)
+ int argc;
+ char *argv[];
+{
+ if (argc == 1) {
+ ntflag = 0;
+ printf("Ntrans off.\n");
+ code = ntflag;
+ return;
+ }
+ ntflag++;
+ code = ntflag;
+ (void) strncpy(ntin, argv[1], 16);
+ ntin[16] = '\0';
+ if (argc == 2) {
+ ntout[0] = '\0';
+ return;
+ }
+ (void) strncpy(ntout, argv[2], 16);
+ ntout[16] = '\0';
+}
+
+char *
+dotrans(name)
+ char *name;
+{
+ static char new[MAXPATHLEN];
+ char *cp1, *cp2 = new;
+ register int i, ostop, found;
+
+ for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++);
+ for (cp1 = name; *cp1; cp1++) {
+ found = 0;
+ for (i = 0; *(ntin + i) && i < 16; i++) {
+ if (*cp1 == *(ntin + i)) {
+ found++;
+ if (i < ostop) {
+ *cp2++ = *(ntout + i);
+ }
+ break;
+ }
+ }
+ if (!found) {
+ *cp2++ = *cp1;
+ }
+ }
+ *cp2 = '\0';
+ return(new);
+}
+
+setnmap(argc, argv)
+ int argc;
+ char *argv[];
+{
+ char *cp;
+
+ if (argc == 1) {
+ mapflag = 0;
+ printf("Nmap off.\n");
+ code = mapflag;
+ return;
+ }
+ if (argc < 3 && !another(&argc, &argv, "mapout")) {
+ printf("Usage: %s [mapin mapout]\n",argv[0]);
+ code = -1;
+ return;
+ }
+ mapflag = 1;
+ code = 1;
+ cp = strchr(altarg, ' ');
+ if (proxy) {
+ while(*++cp == ' ');
+ altarg = cp;
+ cp = strchr(altarg, ' ');
+ }
+ *cp = '\0';
+ (void) strncpy(mapin, altarg, MAXPATHLEN - 1);
+ while (*++cp == ' ');
+ (void) strncpy(mapout, cp, MAXPATHLEN - 1);
+}
+
+char *
+domap(name)
+ char *name;
+{
+ static char new[MAXPATHLEN];
+ register char *cp1 = name, *cp2 = mapin;
+ char *tp[9], *te[9];
+ int i, toks[9], toknum = 0, match = 1;
+
+ for (i=0; i < 9; ++i) {
+ toks[i] = 0;
+ }
+ while (match && *cp1 && *cp2) {
+ switch (*cp2) {
+ case '\\':
+ if (*++cp2 != *cp1) {
+ match = 0;
+ }
+ break;
+ case '$':
+ if (*(cp2+1) >= '1' && (*cp2+1) <= '9') {
+ if (*cp1 != *(++cp2+1)) {
+ toks[toknum = *cp2 - '1']++;
+ tp[toknum] = cp1;
+ while (*++cp1 && *(cp2+1)
+ != *cp1);
+ te[toknum] = cp1;
+ }
+ cp2++;
+ break;
+ }
+ /* FALLTHROUGH */
+ default:
+ if (*cp2 != *cp1) {
+ match = 0;
+ }
+ break;
+ }
+ if (match && *cp1) {
+ cp1++;
+ }
+ if (match && *cp2) {
+ cp2++;
+ }
+ }
+ if (!match && *cp1) /* last token mismatch */
+ {
+ toks[toknum] = 0;
+ }
+ cp1 = new;
+ *cp1 = '\0';
+ cp2 = mapout;
+ while (*cp2) {
+ match = 0;
+ switch (*cp2) {
+ case '\\':
+ if (*(cp2 + 1)) {
+ *cp1++ = *++cp2;
+ }
+ break;
+ case '[':
+LOOP:
+ if (*++cp2 == '$' && isdigit(*(cp2+1))) {
+ if (*++cp2 == '0') {
+ char *cp3 = name;
+
+ while (*cp3) {
+ *cp1++ = *cp3++;
+ }
+ match = 1;
+ }
+ else if (toks[toknum = *cp2 - '1']) {
+ char *cp3 = tp[toknum];
+
+ while (cp3 != te[toknum]) {
+ *cp1++ = *cp3++;
+ }
+ match = 1;
+ }
+ }
+ else {
+ while (*cp2 && *cp2 != ',' &&
+ *cp2 != ']') {
+ if (*cp2 == '\\') {
+ cp2++;
+ }
+ else if (*cp2 == '$' &&
+ isdigit(*(cp2+1))) {
+ if (*++cp2 == '0') {
+ char *cp3 = name;
+
+ while (*cp3) {
+ *cp1++ = *cp3++;
+ }
+ }
+ else if (toks[toknum =
+ *cp2 - '1']) {
+ char *cp3=tp[toknum];
+
+ while (cp3 !=
+ te[toknum]) {
+ *cp1++ = *cp3++;
+ }
+ }
+ }
+ else if (*cp2) {
+ *cp1++ = *cp2++;
+ }
+ }
+ if (!*cp2) {
+ printf("nmap: unbalanced brackets\n");
+ return(name);
+ }
+ match = 1;
+ cp2--;
+ }
+ if (match) {
+ while (*++cp2 && *cp2 != ']') {
+ if (*cp2 == '\\' && *(cp2 + 1)) {
+ cp2++;
+ }
+ }
+ if (!*cp2) {
+ printf("nmap: unbalanced brackets\n");
+ return(name);
+ }
+ break;
+ }
+ switch (*++cp2) {
+ case ',':
+ goto LOOP;
+ case ']':
+ break;
+ default:
+ cp2--;
+ goto LOOP;
+ }
+ break;
+ case '$':
+ if (isdigit(*(cp2 + 1))) {
+ if (*++cp2 == '0') {
+ char *cp3 = name;
+
+ while (*cp3) {
+ *cp1++ = *cp3++;
+ }
+ }
+ else if (toks[toknum = *cp2 - '1']) {
+ char *cp3 = tp[toknum];
+
+ while (cp3 != te[toknum]) {
+ *cp1++ = *cp3++;
+ }
+ }
+ break;
+ }
+ /* intentional drop through */
+ default:
+ *cp1++ = *cp2;
+ break;
+ }
+ cp2++;
+ }
+ *cp1 = '\0';
+ if (!*new) {
+ return(name);
+ }
+ return(new);
+}
+
+setsunique()
+{
+ sunique = !sunique;
+ printf("Store unique %s.\n", onoff(sunique));
+ code = sunique;
+}
+
+setrunique()
+{
+ runique = !runique;
+ printf("Receive unique %s.\n", onoff(runique));
+ code = runique;
+}
+
+/* change directory to perent directory */
+cdup()
+{
+ if (command("CDUP") == ERROR && code == 500) {
+ if (verbose)
+ printf("CDUP command not recognized, trying XCUP\n");
+ (void) command("XCUP");
+ }
+}
+
+/* restart transfer at specific point */
+restart(argc, argv)
+ int argc;
+ char *argv[];
+{
+ extern long atol();
+ if (argc != 2)
+ printf("restart: offset not specified\n");
+ else {
+ restart_point = atol(argv[1]);
+ printf("restarting at %ld. %s\n", restart_point,
+ "execute get, put or append to initiate transfer");
+ }
+}
+
+/* show remote system type */
+syst()
+{
+ (void) command("SYST");
+}
+
+macdef(argc, argv)
+ int argc;
+ char *argv[];
+{
+ char *tmp;
+ int c;
+
+ if (macnum == 16) {
+ printf("Limit of 16 macros have already been defined\n");
+ code = -1;
+ return;
+ }
+ if (argc < 2 && !another(&argc, &argv, "macro name")) {
+ printf("Usage: %s macro_name\n",argv[0]);
+ code = -1;
+ return;
+ }
+ if (interactive) {
+ printf("Enter macro line by line, terminating it with a null line\n");
+ }
+ (void) strncpy(macros[macnum].mac_name, argv[1], 8);
+ if (macnum == 0) {
+ macros[macnum].mac_start = macbuf;
+ }
+ else {
+ macros[macnum].mac_start = macros[macnum - 1].mac_end + 1;
+ }
+ tmp = macros[macnum].mac_start;
+ while (tmp != macbuf+4096) {
+ if ((c = getchar()) == EOF) {
+ printf("macdef:end of file encountered\n");
+ code = -1;
+ return;
+ }
+ if ((*tmp = c) == '\n') {
+ if (tmp == macros[macnum].mac_start) {
+ macros[macnum++].mac_end = tmp;
+ code = 0;
+ return;
+ }
+ if (*(tmp-1) == '\0') {
+ macros[macnum++].mac_end = tmp - 1;
+ code = 0;
+ return;
+ }
+ *tmp = '\0';
+ }
+ tmp++;
+ }
+ while (1) {
+ while ((c = getchar()) != '\n' && c != EOF)
+ /* LOOP */;
+ if (c == EOF || getchar() == '\n') {
+ printf("Macro not defined - 4k buffer exceeded\n");
+ code = -1;
+ return;
+ }
+ }
+}
+
+/*
+ * get size of file on remote machine
+ */
+sizecmd(argc, argv)
+ int argc;
+ char *argv[];
+{
+
+ if (argc < 2 && !another(&argc, &argv, "filename")) {
+ printf("usage: %s filename\n", argv[0]);
+ code = -1;
+ return;
+ }
+ (void) command("SIZE %s", argv[1]);
+}
+
+/*
+ * get last modification time of file on remote machine
+ */
+modtime(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int overbose;
+
+ if (argc < 2 && !another(&argc, &argv, "filename")) {
+ printf("usage: %s filename\n", argv[0]);
+ code = -1;
+ return;
+ }
+ overbose = verbose;
+ if (debug == 0)
+ verbose = -1;
+ if (command("MDTM %s", argv[1]) == COMPLETE) {
+ int yy, mo, day, hour, min, sec;
+ sscanf(reply_string, "%*s %04d%02d%02d%02d%02d%02d", &yy, &mo,
+ &day, &hour, &min, &sec);
+ /* might want to print this in local time */
+ printf("%s\t%02d/%02d/%04d %02d:%02d:%02d GMT\n", argv[1],
+ mo, day, yy, hour, min, sec);
+ } else
+ printf("%s\n", reply_string);
+ verbose = overbose;
+}
+
+/*
+ * show status on reomte machine
+ */
+rmtstatus(argc, argv)
+ int argc;
+ char *argv[];
+{
+ (void) command(argc > 1 ? "STAT %s" : "STAT" , argv[1]);
+}
+
+/*
+ * get file if modtime is more recent than current file
+ */
+newer(argc, argv)
+ int argc;
+ char *argv[];
+{
+ if (getit(argc, argv, -1, "w"))
+ printf("Local file \"%s\" is newer than remote file \"%s\"\n",
+ argv[1], argv[2]);
+}
+
+#ifndef NO_PASSIVE_MODE
+/*
+ * Start up passive mode interaction
+ */
+
+/*VARARGS*/
+setpassive()
+{
+
+ passivemode = !passivemode;
+ printf("Passive mode %s.\n", onoff(passivemode));
+ code = passivemode;
+}
+#endif
diff --git a/src/appl/gssftp/ftp/cmdtab.c b/src/appl/gssftp/ftp/cmdtab.c
new file mode 100644
index 0000000..39d171d
--- /dev/null
+++ b/src/appl/gssftp/ftp/cmdtab.c
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 1985, 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)cmdtab.c 5.10 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+#include <stdio.h>
+#include "ftp_var.h"
+
+/*
+ * User FTP -- Command Tables.
+ */
+int setascii(), setbell(), setbinary(), setdebug(), setform();
+int setglob(), sethash(), setmode(), setpeer(), setport();
+int setprompt(), setstruct();
+int settenex(), settrace(), settype(), setverbose();
+int setlevel(), setclear(), setsafe();
+#ifndef NOENCRYPTION
+int setprivate();
+#endif
+int disconnect(), restart(), reget(), syst();
+int cd(), lcd(), delete(), mdelete(), user();
+int ls(), mls(), get(), mget(), help(), append(), put(), mput();
+int quit(), renamefile(), status();
+int quote(), rmthelp(), shell(), site();
+int pwd(), makedir(), removedir(), setcr();
+int account(), doproxy(), reset(), setcase(), setntrans(), setnmap();
+int setsunique(), setrunique(), cdup(), macdef(), domacro();
+int sizecmd(), modtime(), newer(), rmtstatus();
+int do_chmod(), do_umask(), siteidle();
+#ifndef NO_PASSIVE_MODE
+int setpassive();
+#endif
+
+char accounthelp[] = "send account command to remote server";
+char appendhelp[] = "append to a file";
+char asciihelp[] = "set ascii transfer type";
+char beephelp[] = "beep when command completed";
+char binaryhelp[] = "set binary transfer type";
+char casehelp[] = "toggle mget upper/lower case id mapping";
+char cdhelp[] = "change remote working directory";
+char cduphelp[] = "change remote working directory to parent directory";
+char chmodhelp[] = "change file permissions of remote file";
+char clearhelp[] = "set clear protection level for file transfer";
+char connecthelp[] = "connect to remote ftp";
+char crhelp[] = "toggle carriage return stripping on ascii gets";
+char deletehelp[] = "delete remote file";
+char debughelp[] = "toggle/set debugging mode";
+char dirhelp[] = "list contents of remote directory";
+char disconhelp[] = "terminate ftp session";
+char domachelp[] = "execute macro";
+char formhelp[] = "set file transfer format";
+char globhelp[] = "toggle metacharacter expansion of local file names";
+char hashhelp[] = "toggle printing `#' for each buffer transferred";
+char helphelp[] = "print local help information";
+char idlehelp[] = "get (set) idle timer on remote side";
+char lcdhelp[] = "change local working directory";
+char levelhelp[] = "set protection level for file transfer";
+char lshelp[] = "list contents of remote directory";
+char macdefhelp[] = "define a macro";
+char mdeletehelp[] = "delete multiple files";
+char mdirhelp[] = "list contents of multiple remote directories";
+char mgethelp[] = "get multiple files";
+char mkdirhelp[] = "make directory on the remote machine";
+char mlshelp[] = "list contents of multiple remote directories";
+char modtimehelp[] = "show last modification time of remote file";
+char modehelp[] = "set file transfer mode";
+char mputhelp[] = "send multiple files";
+char newerhelp[] = "get file if remote file is newer than local file ";
+char nlisthelp[] = "nlist contents of remote directory";
+char nmaphelp[] = "set templates for default file name mapping";
+char ntranshelp[] = "set translation table for default file name mapping";
+char porthelp[] = "toggle use of PORT cmd for each data connection";
+#ifndef NOENCRYPTION
+char privatehelp[] = "set private protection level for file transfer";
+#endif
+char prompthelp[] = "force interactive prompting on multiple commands";
+char proxyhelp[] = "issue command on alternate connection";
+char pwdhelp[] = "print working directory on remote machine";
+char quithelp[] = "terminate ftp session and exit";
+char quotehelp[] = "send arbitrary ftp command";
+char receivehelp[] = "receive file";
+char regethelp[] = "get file restarting at end of local file";
+char remotehelp[] = "get help from remote server";
+char renamehelp[] = "rename file";
+char restarthelp[]= "restart file transfer at bytecount";
+char rmdirhelp[] = "remove directory on the remote machine";
+char rmtstatushelp[]="show status of remote machine";
+char runiquehelp[] = "toggle store unique for local files";
+char resethelp[] = "clear queued command replies";
+char safehelp[] = "set safe protection level for file transfer";
+char sendhelp[] = "send one file";
+char sitehelp[] = "send site specific command to remote server\n\t\tTry \"rhelp site\" or \"site help\" for more information";
+char shellhelp[] = "escape to the shell";
+char sizecmdhelp[] = "show size of remote file";
+char statushelp[] = "show current status";
+char structhelp[] = "set file transfer structure";
+char suniquehelp[] = "toggle store unique on remote machine";
+char systemhelp[] = "show remote system type";
+char tenexhelp[] = "set tenex file transfer type";
+char tracehelp[] = "toggle packet tracing";
+char typehelp[] = "set file transfer type";
+char umaskhelp[] = "get (set) umask on remote side";
+char userhelp[] = "send new user information";
+char verbosehelp[] = "toggle verbose mode";
+#ifndef NO_PASSIVE_MODE
+char setpassivehelp[] = "enter passive transfer mode";
+#endif
+
+struct cmd cmdtab[] = {
+ { "!", shellhelp, 0, 0, 0, shell },
+ { "$", domachelp, 1, 0, 0, domacro },
+ { "account", accounthelp, 0, 1, 1, account},
+ { "append", appendhelp, 1, 1, 1, put },
+ { "ascii", asciihelp, 0, 1, 1, setascii },
+ { "bell", beephelp, 0, 0, 0, setbell },
+ { "binary", binaryhelp, 0, 1, 1, setbinary },
+ { "bye", quithelp, 0, 0, 0, quit },
+ { "case", casehelp, 0, 0, 1, setcase },
+ { "cd", cdhelp, 0, 1, 1, cd },
+ { "cdup", cduphelp, 0, 1, 1, cdup },
+ { "chmod", chmodhelp, 0, 1, 1, do_chmod },
+ { "clear", clearhelp, 0, 1, 1, setclear },
+ { "close", disconhelp, 0, 1, 1, disconnect },
+ { "cr", crhelp, 0, 0, 0, setcr },
+ { "delete", deletehelp, 0, 1, 1, delete },
+ { "debug", debughelp, 0, 0, 0, setdebug },
+ { "dir", dirhelp, 1, 1, 1, ls },
+ { "disconnect", disconhelp, 0, 1, 1, disconnect },
+ { "form", formhelp, 0, 1, 1, setform },
+ { "get", receivehelp, 1, 1, 1, get },
+ { "glob", globhelp, 0, 0, 0, setglob },
+ { "hash", hashhelp, 0, 0, 0, sethash },
+ { "help", helphelp, 0, 0, 1, help },
+ { "idle", idlehelp, 0, 1, 1, siteidle },
+ { "image", binaryhelp, 0, 1, 1, setbinary },
+ { "lcd", lcdhelp, 0, 0, 0, lcd },
+ { "ls", lshelp, 1, 1, 1, ls },
+ { "macdef", macdefhelp, 0, 0, 0, macdef },
+ { "mdelete", mdeletehelp, 1, 1, 1, mdelete },
+ { "mdir", mdirhelp, 1, 1, 1, mls },
+ { "mget", mgethelp, 1, 1, 1, mget },
+ { "mkdir", mkdirhelp, 0, 1, 1, makedir },
+ { "mls", mlshelp, 1, 1, 1, mls },
+ { "mode", modehelp, 0, 1, 1, setmode },
+ { "modtime", modtimehelp, 0, 1, 1, modtime },
+ { "mput", mputhelp, 1, 1, 1, mput },
+ { "newer", newerhelp, 1, 1, 1, newer },
+ { "nmap", nmaphelp, 0, 0, 1, setnmap },
+ { "nlist", nlisthelp, 1, 1, 1, ls },
+ { "ntrans", ntranshelp, 0, 0, 1, setntrans },
+ { "open", connecthelp, 0, 0, 1, setpeer },
+#ifndef NO_PASSIVE_MODE
+ { "passive", setpassivehelp, 0, 0, 0, setpassive },
+#endif
+#ifndef NOENCRYPTION
+ { "private", privatehelp, 0, 1, 1, setprivate },
+#endif
+ { "prompt", prompthelp, 0, 0, 0, setprompt },
+ { "protect", levelhelp, 0, 1, 1, setlevel },
+ { "proxy", proxyhelp, 0, 0, 1, doproxy },
+ { "sendport", porthelp, 0, 0, 0, setport },
+ { "put", sendhelp, 1, 1, 1, put },
+ { "pwd", pwdhelp, 0, 1, 1, pwd },
+ { "quit", quithelp, 0, 0, 0, quit },
+ { "quote", quotehelp, 1, 1, 1, quote },
+ { "recv", receivehelp, 1, 1, 1, get },
+ { "reget", regethelp, 1, 1, 1, reget },
+ { "rstatus", rmtstatushelp, 0, 1, 1, rmtstatus },
+ { "rhelp", remotehelp, 0, 1, 1, rmthelp },
+ { "rename", renamehelp, 0, 1, 1, renamefile },
+ { "reset", resethelp, 0, 1, 1, reset },
+ { "restart", restarthelp, 1, 1, 1, restart },
+ { "rmdir", rmdirhelp, 0, 1, 1, removedir },
+ { "runique", runiquehelp, 0, 0, 1, setrunique },
+ { "safe", safehelp, 0, 1, 1, setsafe },
+ { "send", sendhelp, 1, 1, 1, put },
+ { "site", sitehelp, 0, 1, 1, site },
+ { "size", sizecmdhelp, 1, 1, 1, sizecmd },
+ { "status", statushelp, 0, 0, 1, status },
+ { "struct", structhelp, 0, 1, 1, setstruct },
+ { "system", systemhelp, 0, 1, 1, syst },
+ { "sunique", suniquehelp, 0, 0, 1, setsunique },
+ { "tenex", tenexhelp, 0, 1, 1, settenex },
+ { "trace", tracehelp, 0, 0, 0, settrace },
+ { "type", typehelp, 0, 1, 1, settype },
+ { "user", userhelp, 0, 1, 1, user },
+ { "umask", umaskhelp, 0, 1, 1, do_umask },
+ { "verbose", verbosehelp, 0, 0, 0, setverbose },
+ { "?", helphelp, 0, 0, 1, help },
+ { 0 },
+};
+
+int NCMDS = (sizeof (cmdtab) / sizeof (cmdtab[0])) - 1;
diff --git a/src/appl/gssftp/ftp/configure.in b/src/appl/gssftp/ftp/configure.in
new file mode 100644
index 0000000..a03170b
--- /dev/null
+++ b/src/appl/gssftp/ftp/configure.in
@@ -0,0 +1,12 @@
+AC_INIT(ftp.c)
+CONFIG_RULES
+AC_CONST
+AC_PROG_INSTALL
+KRB5_SIGTYPE
+CHECK_SIGPROCMASK
+CHECK_WAIT_TYPE
+AC_FUNC_VFORK
+AC_HAVE_FUNCS(getcwd getdtablesize)
+AC_HEADER_CHECK(termios.h,AC_FUNC_CHECK(cfsetispeed,AC_DEFINE(POSIX_TERMIOS)))
+V5_USE_SHARED_LIB
+V5_AC_OUTPUT_MAKEFILE
diff --git a/src/appl/gssftp/ftp/domacro.c b/src/appl/gssftp/ftp/domacro.c
new file mode 100644
index 0000000..9bc277b
--- /dev/null
+++ b/src/appl/gssftp/ftp/domacro.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 1985 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)domacro.c 1.8 (Berkeley) 9/28/90";
+#endif /* not lint */
+
+#include <stdio.h>
+
+#include "ftp_var.h"
+
+#include <signal.h>
+#include <errno.h>
+#include <ctype.h>
+#include <string.h>
+
+domacro(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register int i, j;
+ register char *cp1, *cp2;
+ int count = 2, loopflg = 0;
+ char line2[200];
+ extern char **glob(), *globerr;
+ struct cmd *getcmd(), *c;
+ extern struct cmd cmdtab[];
+
+ if (argc < 2 && !another(&argc, &argv, "macro name")) {
+ printf("Usage: %s macro_name.\n", argv[0]);
+ code = -1;
+ return;
+ }
+ for (i = 0; i < macnum; ++i) {
+ if (!strncmp(argv[1], macros[i].mac_name, 9)) {
+ break;
+ }
+ }
+ if (i == macnum) {
+ printf("'%s' macro not found.\n", argv[1]);
+ code = -1;
+ return;
+ }
+ (void) strcpy(line2, line);
+TOP:
+ cp1 = macros[i].mac_start;
+ while (cp1 != macros[i].mac_end) {
+ while (isspace(*cp1)) {
+ cp1++;
+ }
+ cp2 = line;
+ while (*cp1 != '\0') {
+ switch(*cp1) {
+ case '\\':
+ *cp2++ = *++cp1;
+ break;
+ case '$':
+ if (isdigit(*(cp1+1))) {
+ j = 0;
+ while (isdigit(*++cp1)) {
+ j = 10*j + *cp1 - '0';
+ }
+ cp1--;
+ if (argc - 2 >= j) {
+ (void) strcpy(cp2, argv[j+1]);
+ cp2 += strlen(argv[j+1]);
+ }
+ break;
+ }
+ if (*(cp1+1) == 'i') {
+ loopflg = 1;
+ cp1++;
+ if (count < argc) {
+ (void) strcpy(cp2, argv[count]);
+ cp2 += strlen(argv[count]);
+ }
+ break;
+ }
+ /* intentional drop through */
+ default:
+ *cp2++ = *cp1;
+ break;
+ }
+ if (*cp1 != '\0') {
+ cp1++;
+ }
+ }
+ *cp2 = '\0';
+ makeargv();
+ c = getcmd(margv[0]);
+ if (c == (struct cmd *)-1) {
+ printf("?Ambiguous command\n");
+ code = -1;
+ }
+ else if (c == 0) {
+ printf("?Invalid command\n");
+ code = -1;
+ }
+ else if (c->c_conn && !connected) {
+ printf("Not connected.\n");
+ code = -1;
+ }
+ else {
+ if (verbose) {
+ printf("%s\n",line);
+ }
+ (*c->c_handler)(margc, margv);
+ if (bell && c->c_bell) {
+ (void) putchar('\007');
+ }
+ (void) strcpy(line, line2);
+ makeargv();
+ argc = margc;
+ argv = margv;
+ }
+ if (cp1 != macros[i].mac_end) {
+ cp1++;
+ }
+ }
+ if (loopflg && ++count < argc) {
+ goto TOP;
+ }
+}
diff --git a/src/appl/gssftp/ftp/ftp.M b/src/appl/gssftp/ftp/ftp.M
new file mode 100644
index 0000000..4629183
--- /dev/null
+++ b/src/appl/gssftp/ftp/ftp.M
@@ -0,0 +1,1200 @@
+.\" Copyright (c) 1985, 1989, 1990 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)ftp.1 6.18 (Berkeley) 7/30/91
+.\"
+.so man1/tmac.doc
+.Dd July 30, 1991
+.Dt FTP 1
+.Os BSD 4.2
+.Sh NAME
+.Nm ftp
+.Nd
+.Tn ARPANET
+file transfer program
+.Sh SYNOPSIS
+.Nm ftp
+.Op Fl v
+.Op Fl d
+.Op Fl i
+.Op Fl n
+.Op Fl g
+.Op Fl k Ar realm
+.Op Ar host
+.Sh DESCRIPTION
+.Nm Ftp
+is the user interface to the
+.Tn ARPANET
+standard File Transfer Protocol.
+The program allows a user to transfer files to and from a
+remote network site.
+.Pp
+Options may be specified at the command line, or to the
+command interpreter.
+.Bl -tag -width flag
+.It Fl v
+Verbose option forces
+.Nm ftp
+to show all responses from the remote server, as well
+as report on data transfer statistics.
+.It Fl n
+Restrains
+.Nm ftp
+from attempting \*(Lqauto-login\*(Rq upon initial connection.
+If auto-login is enabled,
+.Nm ftp
+attempts to authenticate to the
+.Tn FTP
+server by sending the
+.Dv AUTH
+command, using whichever authentication types are locally supported.
+Once an authentication type is accepted, an authentication protocol
+will proceed by issuing
+.Dv ADAT
+commands.
+.Nm ftp
+then
+will check the
+.Pa .netrc
+(see below) file in the user's home directory for an entry describing
+an account on the remote machine.
+If no entry exists,
+.Nm ftp
+will prompt for the remote machine login name (default is the user
+identity on the local machine), and, if necessary, prompt for a password
+and an account with which to login.
+.It Fl i
+Turns off interactive prompting during
+multiple file transfers.
+.It Fl d
+Enables debugging.
+.It Fl g
+Disables file name globbing.
+.It Fl k Ar realm
+When using Kerberos V4 authentication, get tickets in
+.Ar realm.
+.El
+.Pp
+The client host with which
+.Nm ftp
+is to communicate may be specified on the command line.
+If this is done,
+.Nm ftp
+will immediately attempt to establish a connection to an
+.Tn FTP
+server on that host; otherwise,
+.Nm ftp
+will enter its command interpreter and await instructions
+from the user.
+When
+.Nm ftp
+is awaiting commands from the user the prompt
+.Ql ftp>
+is provided to the user.
+The following commands are recognized
+by
+.Nm ftp :
+.Bl -tag -width Fl
+.It Ic \&! Op Ar command Op Ar args
+Invoke an interactive shell on the local machine.
+If there are arguments, the first is taken to be a command to execute
+directly, with the rest of the arguments as its arguments.
+.It Ic \&$ Ar macro-name Op Ar args
+Execute the macro
+.Ar macro-name
+that was defined with the
+.Ic macdef
+command.
+Arguments are passed to the macro unglobbed.
+.It Ic account Op Ar passwd
+Supply a supplemental password required by a remote system for access
+to resources once a login has been successfully completed.
+If no argument is included, the user will be prompted for an account
+password in a non-echoing input mode.
+.It Ic append Ar local-file Op Ar remote-file
+Append a local file to a file on the remote machine.
+If
+.Ar remote-file
+is left unspecified, the local file name is used in naming the
+remote file after being altered by any
+.Ic ntrans
+or
+.Ic nmap
+setting.
+File transfer uses the current settings for
+.Ic type ,
+.Ic format ,
+.Ic mode ,
+and
+.Ic structure .
+.It Ic ascii
+Set the file transfer
+.Ic type
+to network
+.Tn ASCII .
+This is the default type.
+.It Ic bell
+Arrange that a bell be sounded after each file transfer
+command is completed.
+.It Ic binary
+Set the file transfer
+.Ic type
+to support binary image transfer.
+.It Ic bye
+Terminate the
+.Tn FTP
+session with the remote server
+and exit
+.Nm ftp .
+An end of file will also terminate the session and exit.
+.It Ic case
+Toggle remote computer file name case mapping during
+.Ic mget
+commands.
+When
+.Ic case
+is on (default is off), remote computer file names with all letters in
+upper case are written in the local directory with the letters mapped
+to lower case.
+.It Ic \&cd Ar remote-directory
+Change the working directory on the remote machine
+to
+.Ar remote-directory .
+.It Ic cdup
+Change the remote machine working directory to the parent of the
+current remote machine working directory.
+.It Ic chmod Ar mode file-name
+Change the permission modes of the file
+.Ar file-name
+on the remote
+system to
+.Ar mode .
+.It Ic clear
+Set the protection level on data transfers to \*(Lqclear\*(Rq.
+If no
+.Dv ADAT
+command succeeded, then this is the default protection level.
+.It Ic close
+Terminate the
+.Tn FTP
+session with the remote server, and
+return to the command interpreter.
+Any defined macros are erased.
+.It Ic \&cr
+Toggle carriage return stripping during
+ascii type file retrieval.
+Records are denoted by a carriage return/linefeed sequence
+during ascii type file transfer.
+When
+.Ic \&cr
+is on (the default), carriage returns are stripped from this
+sequence to conform with the
+.Ux
+single linefeed record
+delimiter.
+Records on
+.Pf non\- Ns Ux
+remote systems may contain single linefeeds;
+when an ascii type transfer is made, these linefeeds may be
+distinguished from a record delimiter only when
+.Ic \&cr
+is off.
+.It Ic delete Ar remote-file
+Delete the file
+.Ar remote-file
+on the remote machine.
+.It Ic debug Op Ar debug-value
+Toggle debugging mode.
+If an optional
+.Ar debug-value
+is specified it is used to set the debugging level.
+When debugging is on,
+.Nm ftp
+prints each command sent to the remote machine, preceded
+by the string
+.Ql \-\->
+.It Xo
+.Ic dir
+.Op Ar remote-directory
+.Op Ar local-file
+.Xc
+Print a listing of the directory contents in the
+directory,
+.Ar remote-directory ,
+and, optionally, placing the output in
+.Ar local-file .
+If interactive prompting is on,
+.Nm ftp
+will prompt the user to verify that the last argument is indeed the
+target local file for receiving
+.Ic dir
+output.
+If no directory is specified, the current working
+directory on the remote machine is used.
+If no local
+file is specified, or
+.Ar local-file
+is
+.Fl ,
+output comes to the terminal.
+.It Ic disconnect
+A synonym for
+.Ar close .
+.It Ic form Ar format
+Set the file transfer
+.Ic form
+to
+.Ar format .
+The default format is \*(Lqfile\*(Rq.
+.It Ic get Ar remote-file Op Ar local-file
+Retrieve the
+.Ar remote-file
+and store it on the local machine.
+If the local
+file name is not specified, it is given the same
+name it has on the remote machine, subject to
+alteration by the current
+.Ic case ,
+.Ic ntrans ,
+and
+.Ic nmap
+settings.
+The current settings for
+.Ic type ,
+.Ic form ,
+.Ic mode ,
+and
+.Ic structure
+are used while transferring the file.
+.It Ic glob
+Toggle filename expansion for
+.Ic mdelete ,
+.Ic mget
+and
+.Ic mput .
+If globbing is turned off with
+.Ic glob ,
+the file name arguments
+are taken literally and not expanded.
+Globbing for
+.Ic mput
+is done as in
+.Xr csh 1 .
+For
+.Ic mdelete
+and
+.Ic mget ,
+each remote file name is expanded
+separately on the remote machine and the lists are not merged.
+Expansion of a directory name is likely to be
+different from expansion of the name of an ordinary file:
+the exact result depends on the foreign operating system and ftp server,
+and can be previewed by doing
+.Ql mls remote-files \-
+Note:
+.Ic mget
+and
+.Ic mput
+are not meant to transfer
+entire directory subtrees of files.
+That can be done by
+transferring a
+.Xr tar 1
+archive of the subtree (in binary mode).
+.It Ic hash
+Toggle hash-sign (``#'') printing for each data block
+transferred.
+The size of a data block is 1024 bytes.
+.It Ic help Op Ar command
+Print an informative message about the meaning of
+.Ar command .
+If no argument is given,
+.Nm ftp
+prints a list of the known commands.
+.It Ic idle Op Ar seconds
+Set the inactivity timer on the remote server to
+.Ar seconds
+seconds.
+If
+.Ar seconds
+is omitted, the current inactivity timer is printed.
+.It Ic lcd Op Ar directory
+Change the working directory on the local machine.
+If
+no
+.Ar directory
+is specified, the user's home directory is used.
+.It Xo
+.Ic \&ls
+.Op Ar remote-directory
+.Op Ar local-file
+.Xc
+Print a listing of the contents of a
+directory on the remote machine.
+The listing includes any system-dependent information that the server
+chooses to include; for example, most
+.Ux
+systems will produce
+output from the command
+.Ql ls \-l .
+(See also
+.Ic nlist . )
+If
+.Ar remote-directory
+is left unspecified, the current working directory is used.
+If interactive prompting is on,
+.Nm ftp
+will prompt the user to verify that the last argument is indeed the
+target local file for receiving
+.Ic \&ls
+output.
+If no local file is specified, or if
+.Ar local-file
+is
+.Sq Fl ,
+the output is sent to the terminal.
+.It Ic macdef Ns Ar macro-name
+Define a macro.
+Subsequent lines are stored as the macro
+.Ar macro-name ;
+a null line (consecutive newline characters
+in a file or
+carriage returns from the terminal) terminates macro input mode.
+There is a limit of 16 macros and 4096 total characters in all
+defined macros.
+Macros remain defined until a
+.Ic close
+command is executed.
+The macro processor interprets `$' and `\e' as special characters.
+A `$' followed by a number (or numbers) is replaced by the
+corresponding argument on the macro invocation command line.
+A `$' followed by an `i' signals that macro processor that the
+executing macro is to be looped.
+On the first pass `$i' is
+replaced by the first argument on the macro invocation command line,
+on the second pass it is replaced by the second argument, and so on.
+A `\e' followed by any character is replaced by that character.
+Use the `\e' to prevent special treatment of the `$'.
+.It Ic mdelete Op Ar remote-files
+Delete the
+.Ar remote-files
+on the remote machine.
+.It Ic mdir Ar remote-files local-file
+Like
+.Ic dir ,
+except multiple remote files may be specified.
+If interactive prompting is on,
+.Nm ftp
+will prompt the user to verify that the last argument is indeed the
+target local file for receiving
+.Ic mdir
+output.
+.It Ic mget Ar remote-files
+Expand the
+.Ar remote-files
+on the remote machine
+and do a
+.Ic get
+for each file name thus produced.
+See
+.Ic glob
+for details on the filename expansion.
+Resulting file names will then be processed according to
+.Ic case ,
+.Ic ntrans ,
+and
+.Ic nmap
+settings.
+Files are transferred into the local working directory,
+which can be changed with
+.Ql lcd directory ;
+new local directories can be created with
+.Ql "\&! mkdir directory" .
+.It Ic mkdir Ar directory-name
+Make a directory on the remote machine.
+.It Ic mls Ar remote-files local-file
+Like
+.Ic nlist ,
+except multiple remote files may be specified,
+and the
+.Ar local-file
+must be specified.
+If interactive prompting is on,
+.Nm ftp
+will prompt the user to verify that the last argument is indeed the
+target local file for receiving
+.Ic mls
+output.
+.It Ic mode Op Ar mode-name
+Set the file transfer
+.Ic mode
+to
+.Ar mode-name .
+The default mode is \*(Lqstream\*(Rq mode.
+.It Ic modtime Ar file-name
+Show the last modification time of the file on the remote machine.
+.It Ic mput Ar local-files
+Expand wild cards in the list of local files given as arguments
+and do a
+.Ic put
+for each file in the resulting list.
+See
+.Ic glob
+for details of filename expansion.
+Resulting file names will then be processed according to
+.Ic ntrans
+and
+.Ic nmap
+settings.
+.It Ic newer Ar file-name
+Get the file only if the modification time of the remote file is more
+recent that the file on the current system.
+If the file does not
+exist on the current system, the remote file is considered
+.Ic newer .
+Otherwise, this command is identical to
+.Ar get .
+.It Xo
+.Ic nlist
+.Op Ar remote-directory
+.Op Ar local-file
+.Xc
+Print a list of the files in a
+directory on the remote machine.
+If
+.Ar remote-directory
+is left unspecified, the current working directory is used.
+If interactive prompting is on,
+.Nm ftp
+will prompt the user to verify that the last argument is indeed the
+target local file for receiving
+.Ic nlist
+output.
+If no local file is specified, or if
+.Ar local-file
+is
+.Fl ,
+the output is sent to the terminal.
+.It Ic nmap Op Ar inpattern outpattern
+Set or unset the filename mapping mechanism.
+If no arguments are specified, the filename mapping mechanism is unset.
+If arguments are specified, remote filenames are mapped during
+.Ic mput
+commands and
+.Ic put
+commands issued without a specified remote target filename.
+If arguments are specified, local filenames are mapped during
+.Ic mget
+commands and
+.Ic get
+commands issued without a specified local target filename.
+This command is useful when connecting to a
+.No non\- Ns Ux
+remote computer
+with different file naming conventions or practices.
+The mapping follows the pattern set by
+.Ar inpattern
+and
+.Ar outpattern .
+.Op Ar Inpattern
+is a template for incoming filenames (which may have already been
+processed according to the
+.Ic ntrans
+and
+.Ic case
+settings).
+Variable templating is accomplished by including the
+sequences `$1', `$2', ..., `$9' in
+.Ar inpattern .
+Use `\\' to prevent this special treatment of the `$' character.
+All other characters are treated literally, and are used to determine the
+.Ic nmap
+.Op Ar inpattern
+variable values.
+For example, given
+.Ar inpattern
+$1.$2 and the remote file name "mydata.data", $1 would have the value
+"mydata", and $2 would have the value "data".
+The
+.Ar outpattern
+determines the resulting mapped filename.
+The sequences `$1', `$2', ...., `$9' are replaced by any value resulting
+from the
+.Ar inpattern
+template.
+The sequence `$0' is replace by the original filename.
+Additionally, the sequence
+.Ql Op Ar seq1 , Ar seq2
+is replaced by
+.Op Ar seq1
+if
+.Ar seq1
+is not a null string; otherwise it is replaced by
+.Ar seq2 .
+For example, the command
+.Pp
+.Bd -literal -offset indent -compact
+nmap $1.$2.$3 [$1,$2].[$2,file]
+.Ed
+.Pp
+would yield
+the output filename "myfile.data" for input filenames "myfile.data" and
+"myfile.data.old", "myfile.file" for the input filename "myfile", and
+"myfile.myfile" for the input filename ".myfile".
+Spaces may be included in
+.Ar outpattern ,
+as in the example: `nmap $1 sed "s/ *$//" > $1' .
+Use the `\e' character to prevent special treatment
+of the `$','[','[', and `,' characters.
+.It Ic ntrans Op Ar inchars Op Ar outchars
+Set or unset the filename character translation mechanism.
+If no arguments are specified, the filename character
+translation mechanism is unset.
+If arguments are specified, characters in
+remote filenames are translated during
+.Ic mput
+commands and
+.Ic put
+commands issued without a specified remote target filename.
+If arguments are specified, characters in
+local filenames are translated during
+.Ic mget
+commands and
+.Ic get
+commands issued without a specified local target filename.
+This command is useful when connecting to a
+.No non\- Ns Ux
+remote computer
+with different file naming conventions or practices.
+Characters in a filename matching a character in
+.Ar inchars
+are replaced with the corresponding character in
+.Ar outchars .
+If the character's position in
+.Ar inchars
+is longer than the length of
+.Ar outchars ,
+the character is deleted from the file name.
+.It Ic open Ar host Op Ar port
+Establish a connection to the specified
+.Ar host
+.Tn FTP
+server.
+An optional port number may be supplied,
+in which case,
+.Nm ftp
+will attempt to contact an
+.Tn FTP
+server at that port.
+If the
+.Ic auto-login
+option is on (default),
+.Nm ftp
+will attempt to authenticate to the
+.Tn FTP
+server by sending the
+.Dv AUTH
+command, using whichever authentication types which are locally supported.
+Once an authentication type is accepted, an authentication protocol
+will proceed by issuing
+.Dv ADAT
+commands.
+.Nm ftp
+will also attempt to automatically log the user in to
+the
+.Tn FTP
+server (see below).
+.It Ic private
+Set the protection level on data transfers to \*(Lqprivate\*(Rq.
+Data transmissions will now be
+confidentiality and integrity protected by encryption.
+If no
+.Dv ADAT
+command succeeded, then the only possible level is \*(Lqclear\*(Rq.
+.It Ic prompt
+Toggle interactive prompting.
+Interactive prompting
+occurs during multiple file transfers to allow the
+user to selectively retrieve or store files.
+If prompting is turned off (default is on), any
+.Ic mget
+or
+.Ic mput
+will transfer all files, and any
+.Ic mdelete
+will delete all files.
+.It Ic protect Op Ar protection-level
+Set the protection level on data transfers to
+.Ar protection-level .
+The valid protection levels are \*(Lqclear\*(Rq
+for unprotected data transmissions, \*(Lqsafe\*(Rq
+for data transmissions integrity
+protected by cryptographic checksum, and \*(Lqprivate\*(Rq
+for data transmissions confidentiality and integrity
+protected by encryption.
+If no
+.Dv ADAT
+command succeeded, then the only possible level is \*(Lqclear\*(Rq.
+If no level is specified, the current level is printed.
+The default protection level is \*(Lqclear\*(Rq.
+.It Ic proxy Ar ftp-command
+Execute an ftp command on a secondary control connection.
+This command allows simultaneous connection to two remote ftp
+servers for transferring files between the two servers.
+The first
+.Ic proxy
+command should be an
+.Ic open ,
+to establish the secondary control connection.
+Enter the command "proxy ?" to see other ftp commands executable on the
+secondary connection.
+The following commands behave differently when prefaced by
+.Ic proxy :
+.Ic open
+will not define new macros during the auto-login process,
+.Ic close
+will not erase existing macro definitions,
+.Ic get
+and
+.Ic mget
+transfer files from the host on the primary control connection
+to the host on the secondary control connection, and
+.Ic put ,
+.Ic mput ,
+and
+.Ic append
+transfer files from the host on the secondary control connection
+to the host on the primary control connection.
+Third party file transfers depend upon support of the ftp protocol
+.Dv PASV
+command by the server on the secondary control connection.
+.It Ic put Ar local-file Op Ar remote-file
+Store a local file on the remote machine.
+If
+.Ar remote-file
+is left unspecified, the local file name is used
+after processing according to any
+.Ic ntrans
+or
+.Ic nmap
+settings
+in naming the remote file.
+File transfer uses the
+current settings for
+.Ic type ,
+.Ic format ,
+.Ic mode ,
+and
+.Ic structure .
+.It Ic pwd
+Print the name of the current working directory on the remote
+machine.
+.It Ic quit
+A synonym for
+.Ic bye .
+.It Ic quote Ar arg1 arg2 ...
+The arguments specified are sent, verbatim, to the remote
+.Tn FTP
+server.
+.It Ic recv Ar remote-file Op Ar local-file
+A synonym for get.
+.It Ic reget Ar remote-file Op Ar local-file
+Reget acts like get, except that if
+.Ar local-file
+exists and is
+smaller than
+.Ar remote-file ,
+.Ar local-file
+is presumed to be
+a partially transferred copy of
+.Ar remote-file
+and the transfer
+is continued from the apparent point of failure.
+This command
+is useful when transferring very large files over networks that
+are prone to dropping connections.
+.It Ic remotehelp Op Ar command-name
+Request help from the remote
+.Tn FTP
+server.
+If a
+.Ar command-name
+is specified it is supplied to the server as well.
+.It Ic remotestatus Op Ar file-name
+With no arguments, show status of remote machine.
+If
+.Ar file-name
+is specified, show status of
+.Ar file-name
+on remote machine.
+.It Xo
+.Ic rename
+.Op Ar from
+.Op Ar to
+.Xc
+Rename the file
+.Ar from
+on the remote machine, to the file
+.Ar to .
+.It Ic reset
+Clear reply queue.
+This command re-synchronizes command/reply sequencing with the remote
+ftp server.
+Resynchronization may be necessary following a violation of the ftp protocol
+by the remote server.
+.It Ic restart Ar marker
+Restart the immediately following
+.Ic get
+or
+.Ic put
+at the
+indicated
+.Ar marker .
+On
+.Ux
+systems, marker is usually a byte
+offset into the file.
+.It Ic rmdir Ar directory-name
+Delete a directory on the remote machine.
+.It Ic runique
+Toggle storing of files on the local system with unique filenames.
+If a file already exists with a name equal to the target
+local filename for a
+.Ic get
+or
+.Ic mget
+command, a ".1" is appended to the name.
+If the resulting name matches another existing file,
+a ".2" is appended to the original name.
+If this process continues up to ".99", an error
+message is printed, and the transfer does not take place.
+The generated unique filename will be reported.
+Note that
+.Ic runique
+will not affect local files generated from a shell command
+(see below).
+The default value is off.
+.It Ic safe
+Set the protection level on data transfers to \*(Lqsafe\*(Rq.
+Data transmissions will now be
+integrity protected by cryptographic checksum.
+If no
+.Dv ADAT
+command succeeded, then the only possible level is \*(Lqclear\*(Rq.
+.It Ic send Ar local-file Op Ar remote-file
+A synonym for put.
+.It Ic sendport
+Toggle the use of
+.Dv PORT
+commands.
+By default,
+.Nm ftp
+will attempt to use a
+.Dv PORT
+command when establishing
+a connection for each data transfer.
+The use of
+.Dv PORT
+commands can prevent delays
+when performing multiple file transfers.
+If the
+.Dv PORT
+command fails,
+.Nm ftp
+will use the default data port.
+When the use of
+.Dv PORT
+commands is disabled, no attempt will be made to use
+.Dv PORT
+commands for each data transfer.
+This is useful
+for certain
+.Tn FTP
+implementations which do ignore
+.Dv PORT
+commands but, incorrectly, indicate they've been accepted.
+.It Ic site Ar arg1 arg2 ...
+The arguments specified are sent, verbatim, to the remote
+.Tn FTP
+server as a
+.Dv SITE
+command.
+.It Ic size Ar file-name
+Return size of
+.Ar file-name
+on remote machine.
+.It Ic status
+Show the current status of
+.Nm ftp .
+.It Ic struct Op Ar struct-name
+Set the file transfer
+.Ar structure
+to
+.Ar struct-name .
+By default \*(Lqstream\*(Rq structure is used.
+.It Ic sunique
+Toggle storing of files on remote machine under unique file names.
+Remote ftp server must support ftp protocol
+.Dv STOU
+command for
+successful completion.
+The remote server will report unique name.
+Default value is off.
+.It Ic system
+Show the type of operating system running on the remote machine.
+.It Ic tenex
+Set the file transfer type to that needed to
+talk to
+.Tn TENEX
+machines.
+.It Ic trace
+Toggle packet tracing.
+.It Ic type Op Ar type-name
+Set the file transfer
+.Ic type
+to
+.Ar type-name .
+If no type is specified, the current type
+is printed.
+The default type is network
+.Tn ASCII .
+.It Ic umask Op Ar newmask
+Set the default umask on the remote server to
+.Ar newmask .
+If
+.Ar newmask
+is omitted, the current umask is printed.
+.It Xo
+.Ic user Ar user-name
+.Op Ar password
+.Op Ar account
+.Xc
+Identify yourself to the remote
+.Tn FTP
+server.
+If the
+.Ar password
+is not specified and the server requires it,
+.Nm ftp
+will prompt the user for it (after disabling local echo).
+If an
+.Ar account
+field is not specified, and the
+.Tn FTP
+server
+requires it, the user will be prompted for it.
+If an
+.Ar account
+field is specified, an account command will
+be relayed to the remote server after the login sequence
+is completed if the remote server did not require it
+for logging in.
+Unless
+.Nm ftp
+is invoked with \*(Lqauto-login\*(Rq disabled, this
+process is done automatically on initial connection to
+the
+.Tn FTP
+server.
+.It Ic verbose
+Toggle verbose mode.
+In verbose mode, all responses from
+the
+.Tn FTP
+server are displayed to the user.
+In addition,
+if verbose is on, when a file transfer completes, statistics
+regarding the efficiency of the transfer are reported.
+By default,
+verbose is on.
+.It Ic ? Op Ar command
+A synonym for help.
+.El
+.Pp
+Command arguments which have embedded spaces may be quoted with
+quote `"' marks.
+.Sh ABORTING A FILE TRANSFER
+To abort a file transfer, use the terminal interrupt key
+(usually Ctrl-C).
+Sending transfers will be immediately halted.
+Receiving transfers will be halted by sending a ftp protocol
+.Dv ABOR
+command to the remote server, and discarding any further data received.
+The speed at which this is accomplished depends upon the remote
+server's support for
+.Dv ABOR
+processing.
+If the remote server does not support the
+.Dv ABOR
+command, an
+.Ql ftp>
+prompt will not appear until the remote server has completed
+sending the requested file.
+.Pp
+The terminal interrupt key sequence will be ignored when
+.Nm ftp
+has completed any local processing and is awaiting a reply
+from the remote server.
+A long delay in this mode may result from the ABOR processing described
+above, or from unexpected behavior by the remote server, including
+violations of the ftp protocol.
+If the delay results from unexpected remote server behavior, the local
+.Nm ftp
+program must be killed by hand.
+.Sh FILE NAMING CONVENTIONS
+Files specified as arguments to
+.Nm ftp
+commands are processed according to the following rules.
+.Bl -enum
+.It
+If the file name
+.Sq Fl
+is specified, the
+.Ar stdin
+(for reading) or
+.Ar stdout
+(for writing) is used.
+.It
+If the first character of the file name is
+.Sq \&| ,
+the
+remainder of the argument is interpreted as a shell command.
+.Nm Ftp
+then forks a shell, using
+.Xr popen 3
+with the argument supplied, and reads (writes) from the stdout
+(stdin).
+If the shell command includes spaces, the argument
+must be quoted; e.g.
+\*(Lq" ls -lt"\*(Rq.
+A particularly
+useful example of this mechanism is: \*(Lqdir more\*(Rq.
+.It
+Failing the above checks, if ``globbing'' is enabled,
+local file names are expanded
+according to the rules used in the
+.Xr csh 1 ;
+c.f. the
+.Ic glob
+command.
+If the
+.Nm ftp
+command expects a single local file (.e.g.
+.Ic put ) ,
+only the first filename generated by the "globbing" operation is used.
+.It
+For
+.Ic mget
+commands and
+.Ic get
+commands with unspecified local file names, the local filename is
+the remote filename, which may be altered by a
+.Ic case ,
+.Ic ntrans ,
+or
+.Ic nmap
+setting.
+The resulting filename may then be altered if
+.Ic runique
+is on.
+.It
+For
+.Ic mput
+commands and
+.Ic put
+commands with unspecified remote file names, the remote filename is
+the local filename, which may be altered by a
+.Ic ntrans
+or
+.Ic nmap
+setting.
+The resulting filename may then be altered by the remote server if
+.Ic sunique
+is on.
+.El
+.Sh FILE TRANSFER PARAMETERS
+The FTP specification specifies many parameters which may
+affect a file transfer.
+The
+.Ic type
+may be one of \*(Lqascii\*(Rq, \*(Lqimage\*(Rq (binary),
+\*(Lqebcdic\*(Rq, and \*(Lqlocal byte size\*(Rq (for
+.Tn PDP Ns -10's
+and
+.Tn PDP Ns -20's
+mostly).
+.Nm Ftp
+supports the ascii and image types of file transfer,
+plus local byte size 8 for
+.Ic tenex
+mode transfers.
+.Pp
+.Nm Ftp
+supports only the default values for the remaining
+file transfer parameters:
+.Ic mode ,
+.Ic form ,
+and
+.Ic struct .
+.Sh THE .netrc FILE
+The
+.Pa .netrc
+file contains login and initialization information
+used by the auto-login process.
+It resides in the user's home directory.
+The following tokens are recognized; they may be separated by spaces,
+tabs, or new-lines:
+.Bl -tag -width password
+.It Ic machine Ar name
+Identify a remote machine
+.Ar name .
+The auto-login process searches the
+.Pa .netrc
+file for a
+.Ic machine
+token that matches the remote machine specified on the
+.Nm ftp
+command line or as an
+.Ic open
+command argument.
+Once a match is made, the subsequent
+.Pa .netrc
+tokens are processed,
+stopping when the end of file is reached or another
+.Ic machine
+or a
+.Ic default
+token is encountered.
+.It Ic default
+This is the same as
+.Ic machine
+.Ar name
+except that
+.Ic default
+matches any name.
+There can be only one
+.Ic default
+token, and it must be after all
+.Ic machine
+tokens.
+This is normally used as:
+.Pp
+.Dl default login anonymous password user@site
+.Pp
+thereby giving the user
+.Ar automatic
+anonymous ftp login to
+machines not specified in
+.Pa .netrc .
+This can be overridden
+by using the
+.Fl n
+flag to disable auto-login.
+.It Ic login Ar name
+Identify a user on the remote machine.
+If this token is present, the auto-login process will initiate
+a login using the specified
+.Ar name .
+.It Ic password Ar string
+Supply a password.
+If this token is present, the auto-login process will supply the
+specified string if the remote server requires a password as part
+of the login process.
+Note that if this token is present in the
+.Pa .netrc
+file for any user other
+than
+.Ar anonymous ,
+.Nm ftp
+will abort the auto-login process if the
+.Pa .netrc
+is readable by
+anyone besides the user.
+.It Ic account Ar string
+Supply an additional account password.
+If this token is present, the auto-login process will supply the
+specified string if the remote server requires an additional
+account password, or the auto-login process will initiate an
+.Dv ACCT
+command if it does not.
+.It Ic macdef Ar name
+Define a macro.
+This token functions like the
+.Nm ftp
+.Ic macdef
+command functions.
+A macro is defined with the specified name; its contents begin with the
+next
+.Pa .netrc
+line and continue until a null line (consecutive new-line
+characters) is encountered.
+If a macro named
+.Ic init
+is defined, it is automatically executed as the last step in the
+auto-login process.
+.El
+.Sh ENVIRONMENT
+.Nm Ftp
+utilizes the following environment variables.
+.Bl -tag -width Fl
+.It Ev HOME
+For default location of a
+.Pa .netrc
+file, if one exists.
+.It Ev SHELL
+For default shell.
+.El
+.Sh SEE ALSO
+.Xr ftpd 8
+.Pp
+Lunt, S. J.,
+FTP Security Extensions,
+Internet Draft,
+November 1993.
+.Sh HISTORY
+The
+.Nm ftp
+command appeared in
+.Bx 4.2 .
+.Sh BUGS
+Correct execution of many commands depends upon proper behavior
+by the remote server.
+.Pp
+An error in the treatment of carriage returns
+in the
+.Bx 4.2
+ascii-mode transfer code
+has been corrected.
+This correction may result in incorrect transfers of binary files
+to and from
+.Bx 4.2
+servers using the ascii type.
+Avoid this problem by using the binary image type.
diff --git a/src/appl/gssftp/ftp/ftp.c b/src/appl/gssftp/ftp/ftp.c
new file mode 100644
index 0000000..6f778ab
--- /dev/null
+++ b/src/appl/gssftp/ftp/ftp.c
@@ -0,0 +1,2147 @@
+/*
+ * Copyright (c) 1985, 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ftp.c 5.38 (Berkeley) 4/22/91";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/file.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <arpa/ftp.h>
+#include <arpa/telnet.h>
+
+#include <stdio.h>
+#include <signal.h>
+#include <string.h>
+#include <errno.h>
+#include <netdb.h>
+#include <fcntl.h>
+#include <pwd.h>
+#ifndef STDARG
+#if defined(__STDC__) && ! defined(VARARGS)
+#define STDARG
+#endif
+#endif
+#ifdef STDARG
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+#ifdef POSIX
+#include <stdlib.h>
+#endif
+
+#ifndef L_SET
+#define L_SET 0
+#endif
+#ifndef L_INCR
+#define L_INCR 1
+#endif
+
+#ifdef KERBEROS
+#include <krb.h>
+
+KTEXT_ST ticket;
+CREDENTIALS cred;
+Key_schedule schedule;
+MSG_DAT msg_data;
+#endif /* KERBEROS */
+#ifdef GSSAPI
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_generic.h>
+gss_ctx_id_t gcontext;
+#endif /* GSSAPI */
+
+
+static int kerror; /* XXX needed for all auth types */
+
+char *auth_type; /* Authentication succeeded? If so, what type? */
+
+unsigned int maxbuf, actualbuf;
+unsigned char *ucbuf;
+
+#define DEFINITIONS
+#include "ftp_var.h"
+
+#define sig_t my_sig_t
+#define sigtype krb5_sigtype
+typedef sigtype (*sig_t)();
+
+struct sockaddr_in hisctladdr;
+struct sockaddr_in hisdataaddr;
+struct sockaddr_in data_addr;
+int data = -1;
+int abrtflag = 0;
+int ptflag = 0;
+struct sockaddr_in myctladdr;
+uid_t getuid();
+sig_t lostpeer();
+off_t restart_point = 0;
+
+#define strerror(error) (sys_errlist[error])
+extern char *sys_errlist[];
+extern int connected, errno;
+
+#define herror() printf("unknown host\n")
+
+FILE *cin, *cout;
+FILE *dataconn();
+
+char *
+hookup(host, port)
+ char *host;
+ int port;
+{
+ register struct hostent *hp = 0;
+ int s, len, tos;
+ static char hostnamebuf[80];
+
+ memset((char *)&hisctladdr, 0, sizeof (hisctladdr));
+ hisctladdr.sin_addr.s_addr = inet_addr(host);
+ if (hisctladdr.sin_addr.s_addr != -1) {
+ hisctladdr.sin_family = AF_INET;
+ (void) strncpy(hostnamebuf, host, sizeof(hostnamebuf));
+ } else {
+ hp = gethostbyname(host);
+ if (hp == NULL) {
+ fprintf(stderr, "ftp: %s: ", host);
+ herror();
+ code = -1;
+ return((char *) 0);
+ }
+ hisctladdr.sin_family = hp->h_addrtype;
+ memcpy((caddr_t)&hisctladdr.sin_addr, hp->h_addr_list[0],
+ hp->h_length);
+ (void) strncpy(hostnamebuf, hp->h_name, sizeof(hostnamebuf));
+ }
+ hostname = hostnamebuf;
+ s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
+ if (s < 0) {
+ perror("ftp: socket");
+ code = -1;
+ return (0);
+ }
+ hisctladdr.sin_port = port;
+ while (connect(s, (struct sockaddr *)&hisctladdr, sizeof (hisctladdr)) < 0) {
+ if (hp && hp->h_addr_list[1]) {
+ int oerrno = errno;
+ extern char *inet_ntoa();
+
+ fprintf(stderr, "ftp: connect to address %s: ",
+ inet_ntoa(hisctladdr.sin_addr));
+ errno = oerrno;
+ perror((char *) 0);
+ hp->h_addr_list++;
+ memcpy((caddr_t)&hisctladdr.sin_addr,
+ hp->h_addr_list[0], hp->h_length);
+ fprintf(stdout, "Trying %s...\n",
+ inet_ntoa(hisctladdr.sin_addr));
+ (void) close(s);
+ s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
+ if (s < 0) {
+ perror("ftp: socket");
+ code = -1;
+ return (0);
+ }
+ continue;
+ }
+ perror("ftp: connect");
+ code = -1;
+ goto bad;
+ }
+ len = sizeof (myctladdr);
+ if (getsockname(s, (struct sockaddr *)&myctladdr, &len) < 0) {
+ perror("ftp: getsockname");
+ code = -1;
+ goto bad;
+ }
+#ifdef IP_TOS
+#ifdef IPTOS_LOWDELAY
+ tos = IPTOS_LOWDELAY;
+ if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
+ perror("ftp: setsockopt TOS (ignored)");
+#endif
+#endif
+ cin = fdopen(s, "r");
+ cout = fdopen(s, "w");
+ if (cin == NULL || cout == NULL) {
+ fprintf(stderr, "ftp: fdopen failed.\n");
+ if (cin)
+ (void) fclose(cin);
+ if (cout)
+ (void) fclose(cout);
+ code = -1;
+ goto bad;
+ }
+ if (verbose)
+ printf("Connected to %s.\n", hostname);
+ if (getreply(0) > 2) { /* read startup message from server */
+ if (cin)
+ (void) fclose(cin);
+ if (cout)
+ (void) fclose(cout);
+ code = -1;
+ goto bad;
+ }
+#ifdef SO_OOBINLINE
+ {
+ int on = 1;
+
+ if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on))
+ < 0 && debug) {
+ perror("ftp: setsockopt");
+ }
+ }
+#endif /* SO_OOBINLINE */
+
+ return (hostname);
+bad:
+ (void) close(s);
+ return ((char *)0);
+}
+
+login(host)
+ char *host;
+{
+ char tmp[80];
+ char *user, *pass, *acct, *getenv(), *getlogin(), *mygetpass();
+ int n, aflag = 0;
+
+ do_auth();
+ user = pass = acct = 0;
+ if (ruserpass(host, &user, &pass, &acct) < 0) {
+ code = -1;
+ return(0);
+ }
+ while (user == NULL) {
+ char *myname;
+
+ myname = getenv("LOGNAME");
+ if (myname == NULL)
+ myname = getenv("USER");
+ if (myname == NULL)
+ myname = getlogin();
+ if (myname == NULL) {
+ struct passwd *pp = getpwuid(getuid());
+
+ if (pp != NULL)
+ myname = pp->pw_name;
+ }
+ if (myname)
+ printf("Name (%s:%s): ", host, myname);
+ else
+ printf("Name (%s): ", host);
+ (void) fgets(tmp, sizeof(tmp) - 1, stdin);
+ tmp[strlen(tmp) - 1] = '\0';
+ if (*tmp == '\0')
+ user = myname;
+ else
+ user = tmp;
+ }
+ n = command("USER %s", user);
+ if (n == COMPLETE)
+ n = command("PASS dummy");
+ else if (n == CONTINUE) {
+#ifndef NOENCRYPTION
+ int oldlevel;
+#endif
+ if (pass == NULL)
+ pass = mygetpass("Password:");
+#ifndef NOENCRYPTION
+ if ((oldlevel = level) == PROT_S) level = PROT_P;
+#endif
+ n = command("PASS %s", pass);
+#ifndef NOENCRYPTION
+ /* level may have changed */
+ if (level == PROT_P) level = oldlevel;
+#endif
+ }
+ if (n == CONTINUE) {
+ aflag++;
+ acct = mygetpass("Account:");
+ n = command("ACCT %s", acct);
+ }
+ if (n != COMPLETE) {
+ fprintf(stderr, "Login failed.\n");
+ return (0);
+ }
+ if (!aflag && acct != NULL)
+ (void) command("ACCT %s", acct);
+ if (proxy)
+ return(1);
+ for (n = 0; n < macnum; ++n) {
+ if (!strcmp("init", macros[n].mac_name)) {
+ (void) strcpy(line, "$init");
+ makeargv();
+ domacro(margc, margv);
+ break;
+ }
+ }
+ return (1);
+}
+
+sigtype
+cmdabort(sig)
+ int sig;
+{
+ extern jmp_buf ptabort;
+
+ printf("\n");
+ (void) fflush(stdout);
+ abrtflag++;
+ if (ptflag)
+ longjmp(ptabort,1);
+}
+
+secure_command(cmd)
+ char *cmd;
+{
+ char in[FTP_BUFSIZ], out[FTP_BUFSIZ];
+ int length;
+
+ if (auth_type) {
+ /*
+ * File protection level also determines whether
+ * commands are MIC or ENC. Should be independent ...
+ */
+#ifdef KERBEROS
+ if (strcmp(auth_type, "KERBEROS_V4") == 0)
+ if ((length = level == PROT_P ?
+ krb_mk_priv((unsigned char *)cmd, (unsigned char *)out,
+ strlen(cmd), schedule,
+ &cred.session, &myctladdr, &hisctladdr)
+ : krb_mk_safe((unsigned char *)cmd, (unsigned char *)out,
+ strlen(cmd), &cred.session,
+ &myctladdr, &hisctladdr)) == -1) {
+ fprintf(stderr, "krb_mk_%s failed for KERBEROS_V4\n",
+ level == PROT_P ? "priv" : "safe");
+ return(0);
+ }
+#endif /* KERBEROS */
+#ifdef GSSAPI
+ /* secure_command (based on level) */
+ if (strcmp(auth_type, "GSSAPI") == 0) {
+ gss_buffer_desc in_buf, out_buf;
+ OM_uint32 maj_stat, min_stat;
+ int conf_state;
+/* level = PROT_P; */
+ in_buf.value = cmd;
+ in_buf.length = strlen(cmd) + 1;
+ maj_stat = gss_seal(&min_stat, gcontext,
+ (level==PROT_P), /* confidential */
+ GSS_C_QOP_DEFAULT,
+ &in_buf, &conf_state,
+ &out_buf);
+ if (maj_stat != GSS_S_COMPLETE) {
+ /* generally need to deal */
+ user_gss_error(maj_stat, min_stat,
+ (level==PROT_P)?
+ "gss_seal ENC didn't complete":
+ "gss_seal MIC didn't complete");
+ } else if ((level == PROT_P) && !conf_state) {
+ fprintf(stderr,
+ "GSSAPI didn't encrypt message");
+ } else {
+ if (debug)
+ fprintf(stderr, "sealed (%s) %d bytes\n",
+ level==PROT_P?"ENC":"MIC",
+ out_buf.length);
+ memcpy(out, out_buf.value,
+ length=out_buf.length);
+ gss_release_buffer(&min_stat, &out_buf);
+ }
+ }
+#endif /* GSSAPI */
+ /* Other auth types go here ... */
+ if (kerror = radix_encode(out, in, &length, 0)) {
+ fprintf(stderr,"Couldn't base 64 encode command (%s)\n",
+ radix_error(kerror));
+ return(0);
+ }
+ fprintf(cout, "%s %s", level == PROT_P ? "ENC" : "MIC", in);
+ if(debug)
+ fprintf(stderr, "secure_command(%s)\nencoding %d bytes %s %s\n",
+ cmd, length, level==PROT_P ? "ENC" : "MIC", in);
+ } else fputs(cmd, cout);
+ fprintf(cout, "\r\n");
+ (void) fflush(cout);
+ return(1);
+}
+
+#ifdef STDARG
+command(char *fmt, ...)
+#else
+/*VARARGS*/
+command(va_alist)
+va_dcl
+#endif
+{
+ char in[FTP_BUFSIZ];
+ va_list ap;
+#ifndef STDARG
+ char *fmt;
+#endif
+ int r;
+ sig_t oldintr;
+ sigtype cmdabort();
+
+ abrtflag = 0;
+ if (debug) {
+ if (proxflag) printf("%s ", hostname);
+ printf("---> ");
+#ifdef STDARG
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+ fmt = va_arg(ap, char *);
+#endif
+ if (strncmp("PASS ", fmt, 5) == 0)
+ printf("PASS XXXX");
+ else
+ vfprintf(stdout, fmt, ap);
+ va_end(ap);
+ printf("\n");
+ (void) fflush(stdout);
+ }
+ if (cout == NULL) {
+ perror ("No control connection for command");
+ code = -1;
+ return (0);
+ }
+ oldintr = signal(SIGINT, cmdabort);
+#ifdef STDARG
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+ fmt = va_arg(ap, char *);
+#endif
+ vsprintf(in, fmt, ap);
+ va_end(ap);
+again: if (secure_command(in) == 0)
+ return(0);
+ cpend = 1;
+ r = getreply(!strcmp(fmt, "QUIT"));
+#ifndef NOENCRYPTION
+ if (r == 533 && level == PROT_P) {
+ fprintf(stderr,
+ "ENC command not supported at server; retrying under MIC...\n");
+ level = PROT_S;
+ goto again;
+ }
+#endif
+ if (abrtflag && oldintr != SIG_IGN)
+ (*oldintr)(SIGINT);
+ (void) signal(SIGINT, oldintr);
+ return(r);
+}
+
+char reply_string[FTP_BUFSIZ]; /* last line of previous reply */
+
+/* for parsing replies to the ADAT command */
+char *reply_parse, reply_buf[FTP_BUFSIZ], *reply_ptr;
+
+#include <ctype.h>
+
+getreply(expecteof)
+ int expecteof;
+{
+ register int i, c, n;
+ register int dig;
+ register char *cp;
+ int originalcode = 0, continuation = 0;
+ sig_t oldintr;
+ int pflag = 0;
+ char *pt = pasv;
+ sigtype cmdabort();
+ char ibuf[FTP_BUFSIZ], obuf[FTP_BUFSIZ];
+ int safe = 0;
+ extern char *strpbrk(), *strstr();
+
+ ibuf[0] = '\0';
+ if (reply_parse) reply_ptr = reply_buf;
+ oldintr = signal(SIGINT, cmdabort);
+ for (;;) {
+ obuf[0] = '\0';
+ dig = n = code = i = 0;
+ cp = reply_string;
+ while ((c = ibuf[0] ? ibuf[i++] : getc(cin)) != '\n') {
+ if (c == IAC) { /* handle telnet commands */
+ switch (c = getc(cin)) {
+ case WILL:
+ case WONT:
+ c = getc(cin);
+ fprintf(cout, "%c%c%c", IAC, DONT, c);
+ (void) fflush(cout);
+ break;
+ case DO:
+ case DONT:
+ c = getc(cin);
+ fprintf(cout, "%c%c%c", IAC, WONT, c);
+ (void) fflush(cout);
+ break;
+ default:
+ break;
+ }
+ continue;
+ }
+ dig++;
+ if (c == EOF) {
+ if (expecteof) {
+ (void) signal(SIGINT,oldintr);
+ code = 221;
+ return (0);
+ }
+ lostpeer();
+ if (verbose) {
+ printf("421 Service not available, remote server has closed connection\n");
+ (void) fflush(stdout);
+ }
+ code = 421;
+ return(4);
+ }
+ if (n == 0)
+ n = c;
+ if (auth_type && !ibuf[0] &&
+ (n == '6' || continuation)) {
+ if (c != '\r' && dig > 4)
+ obuf[i++] = c;
+ } else {
+ if (auth_type && !ibuf[0] && dig == 1 && verbose)
+ printf("Unauthenticated reply received from server:\n");
+ if (reply_parse) *reply_ptr++ = c;
+ if (c != '\r' && (verbose > 0 ||
+ (verbose > -1 && n == '5' && dig > 4))) {
+ if (proxflag &&
+ (dig == 1 || dig == 5 && verbose == 0))
+ printf("%s:",hostname);
+ (void) putchar(c);
+ }
+ }
+ if (auth_type && !ibuf[0] && n != '6') continue;
+ if (dig < 4 && isdigit(c))
+ code = code * 10 + (c - '0');
+ if (!pflag && code == 227)
+ pflag = 1;
+ if (dig > 4 && pflag == 1 && isdigit(c))
+ pflag = 2;
+ if (pflag == 2) {
+ if (c != '\r' && c != ')')
+ *pt++ = c;
+ else {
+ *pt = '\0';
+ pflag = 3;
+ }
+ }
+ if (dig == 4 && c == '-' && n != '6') {
+ if (continuation)
+ code = 0;
+ continuation++;
+ }
+ if (cp < &reply_string[sizeof(reply_string) - 1])
+ *cp++ = c;
+ }
+ if (auth_type && !ibuf[0] && n != '6')
+ return(getreply(expecteof));
+ ibuf[0] = obuf[i] = '\0';
+ if (code && n == '6')
+ if (code != 631 && code != 632 && code != 633)
+ printf("Unknown reply: %d %s\n", code, obuf);
+ else safe = code == 631;
+ if (obuf[0]) /* if there is a string to decode */
+ if (!auth_type)
+ printf("Cannot decode reply:\n%d %s\n", code, obuf);
+#ifdef NOENCRYPTION
+ else if (code == 632)
+ printf("Cannot decrypt %d reply: %s\n", code, obuf);
+#endif
+#ifdef NOCONFIDENTIAL
+ else if (code == 633)
+ printf("Cannot decrypt %d reply: %s\n", code, obuf);
+#endif
+ else {
+ int len;
+ if (kerror = radix_encode(obuf, ibuf, &len, 1))
+ printf("Can't base 64 decode reply %d (%s)\n\"%s\"\n",
+ code, radix_error(kerror), obuf);
+#ifdef KERBEROS
+ else if (strcmp(auth_type, "KERBEROS_V4") == 0)
+ if ((kerror = safe ?
+ krb_rd_safe((unsigned char *)ibuf, len,
+ &cred.session,
+ &hisctladdr, &myctladdr, &msg_data)
+ : krb_rd_priv((unsigned char *)ibuf, len,
+ schedule, &cred.session,
+ &hisctladdr, &myctladdr, &msg_data))
+ != KSUCCESS)
+ printf("%d reply %s! (krb_rd_%s: %s)\n", code,
+ safe ? "modified" : "garbled",
+ safe ? "safe" : "priv",
+ krb_get_err_text(kerror));
+ else {
+ if (verbose) printf("%c:", safe ? 'S' : 'P');
+ memcpy(ibuf, msg_data.app_data,
+ msg_data.app_length);
+ strcpy(&ibuf[msg_data.app_length], "\r\n");
+ continue;
+ }
+#endif
+#ifdef GSSAPI
+ else if (strcmp(auth_type, "GSSAPI") == 0) {
+ gss_buffer_desc xmit_buf, msg_buf;
+ OM_uint32 maj_stat, min_stat;
+ int conf_state;
+ xmit_buf.value = ibuf;
+ xmit_buf.length = len;
+ /* decrypt/verify the message */
+ conf_state = safe;
+ maj_stat = gss_unseal(&min_stat, gcontext,
+ &xmit_buf, &msg_buf,
+ &conf_state, NULL);
+ if (maj_stat != GSS_S_COMPLETE) {
+ user_gss_error(maj_stat, min_stat,
+ "failed unsealing reply");
+ } else {
+ memcpy(ibuf, msg_buf.value,
+ msg_buf.length);
+ strcpy(&ibuf[msg_buf.length], "\r\n");
+ gss_release_buffer(&min_stat,&msg_buf);
+ continue;
+ }
+ }
+#endif
+ /* Other auth types go here... */
+ }
+ else
+ if (verbose > 0 || verbose > -1 && n == '5') {
+ (void) putchar(c);
+ (void) fflush (stdout);
+ }
+ if (continuation && code != originalcode) {
+ if (originalcode == 0)
+ originalcode = code;
+ continue;
+ }
+ *cp = '\0';
+ if (n != '1')
+ cpend = 0;
+ (void) signal(SIGINT,oldintr);
+ if (code == 421 || originalcode == 421)
+ lostpeer();
+ if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN)
+ (*oldintr)(SIGINT);
+ if (reply_parse) {
+ *reply_ptr = '\0';
+ if (reply_ptr = strstr(reply_buf, reply_parse)) {
+ reply_parse = reply_ptr + strlen(reply_parse);
+ if (reply_ptr = strpbrk(reply_parse, " \r"))
+ *reply_ptr = '\0';
+ } else reply_parse = reply_ptr;
+ }
+ return (n - '0');
+ }
+}
+
+empty(mask, sec)
+ struct fd_set *mask;
+ int sec;
+{
+ struct timeval t;
+
+ t.tv_sec = (long) sec;
+ t.tv_usec = 0;
+ return(select(32, mask, (struct fd_set *) 0, (struct fd_set *) 0, &t));
+}
+
+jmp_buf sendabort;
+
+sigtype
+abortsend(sig)
+ int sig;
+{
+
+ mflag = 0;
+ abrtflag = 0;
+ printf("\nsend aborted\nwaiting for remote to finish abort\n");
+ (void) fflush(stdout);
+ longjmp(sendabort, 1);
+}
+
+#ifdef STDARG
+secure_error(char *fmt, ...)
+#else
+/* VARARGS1 */
+secure_error(fmt, p1, p2, p3, p4, p5)
+ char *fmt;
+#endif
+{
+#ifdef STDARG
+ va_list ap;
+
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+#else
+ fprintf(stderr, fmt, p1, p2, p3, p4, p5);
+#endif
+ putc('\n', stderr);
+}
+
+#define HASHBYTES 1024
+
+sendrequest(cmd, local, remote, printnames)
+ char *cmd, *local, *remote;
+ int printnames;
+{
+ struct stat st;
+ struct timeval start, stop;
+ register int c, d;
+ FILE *fin, *dout = 0, *popen();
+ int (*closefunc)(), pclose(), fclose();
+ sig_t oldintr, oldintp;
+ long bytes = 0, hashbytes = HASHBYTES;
+ char *lmode, buf[FTP_BUFSIZ], *bufp;
+ sigtype abortsend();
+
+ if (verbose && printnames) {
+ if (local && *local != '-')
+ printf("local: %s ", local);
+ if (remote)
+ printf("remote: %s\n", remote);
+ }
+ if (proxy) {
+ proxtrans(cmd, local, remote);
+ return;
+ }
+ if (curtype != type)
+ changetype(type, 0);
+ closefunc = NULL;
+ oldintr = NULL;
+ oldintp = NULL;
+ lmode = "w";
+ if (setjmp(sendabort)) {
+ while (cpend) {
+ (void) getreply(0);
+ }
+ if (data >= 0) {
+ (void) close(data);
+ data = -1;
+ }
+ if (oldintr)
+ (void) signal(SIGINT,oldintr);
+ if (oldintp)
+ (void) signal(SIGPIPE,oldintp);
+ code = -1;
+ return;
+ }
+ oldintr = signal(SIGINT, abortsend);
+ if (strcmp(local, "-") == 0)
+ fin = stdin;
+ else if (*local == '|') {
+ oldintp = signal(SIGPIPE,SIG_IGN);
+ fin = popen(local + 1, "r");
+ if (fin == NULL) {
+ perror(local + 1);
+ (void) signal(SIGINT, oldintr);
+ (void) signal(SIGPIPE, oldintp);
+ code = -1;
+ return;
+ }
+ closefunc = pclose;
+ } else {
+ fin = fopen(local, "r");
+ if (fin == NULL) {
+ fprintf(stderr, "local: %s: %s\n", local,
+ strerror(errno));
+ (void) signal(SIGINT, oldintr);
+ code = -1;
+ return;
+ }
+ closefunc = fclose;
+ if (fstat(fileno(fin), &st) < 0 ||
+ (st.st_mode&S_IFMT) != S_IFREG) {
+ fprintf(stdout, "%s: not a plain file.\n", local);
+ (void) signal(SIGINT, oldintr);
+ fclose(fin);
+ code = -1;
+ return;
+ }
+ }
+ if (initconn()) {
+ (void) signal(SIGINT, oldintr);
+ if (oldintp)
+ (void) signal(SIGPIPE, oldintp);
+ code = -1;
+ if (closefunc != NULL)
+ (*closefunc)(fin);
+ return;
+ }
+ if (setjmp(sendabort))
+ goto abort;
+
+ if (restart_point &&
+ (strcmp(cmd, "STOR") == 0 || strcmp(cmd, "APPE") == 0)) {
+ if (fseek(fin, (long) restart_point, 0) < 0) {
+ fprintf(stderr, "local: %s: %s\n", local,
+ strerror(errno));
+ restart_point = 0;
+ if (closefunc != NULL)
+ (*closefunc)(fin);
+ return;
+ }
+ if (command("REST %ld", (long) restart_point)
+ != CONTINUE) {
+ restart_point = 0;
+ if (closefunc != NULL)
+ (*closefunc)(fin);
+ return;
+ }
+ restart_point = 0;
+ lmode = "r+w";
+ }
+ if (remote) {
+ if (command("%s %s", cmd, remote) != PRELIM) {
+ (void) signal(SIGINT, oldintr);
+ if (oldintp)
+ (void) signal(SIGPIPE, oldintp);
+ if (closefunc != NULL)
+ (*closefunc)(fin);
+ return;
+ }
+ } else
+ if (command("%s", cmd) != PRELIM) {
+ (void) signal(SIGINT, oldintr);
+ if (oldintp)
+ (void) signal(SIGPIPE, oldintp);
+ if (closefunc != NULL)
+ (*closefunc)(fin);
+ return;
+ }
+ dout = dataconn(lmode);
+ if (dout == NULL)
+ goto abort;
+ (void) gettimeofday(&start, (struct timezone *)0);
+ oldintp = signal(SIGPIPE, SIG_IGN);
+ switch (curtype) {
+
+ case TYPE_I:
+ case TYPE_L:
+ errno = d = 0;
+ while ((c = read(fileno(fin), buf, sizeof (buf))) > 0) {
+ bytes += c;
+ for (bufp = buf; c > 0; c -= d, bufp += d)
+ if ((d = secure_write(fileno(dout), bufp, c)) <= 0)
+ break;
+ if (hash) {
+ while (bytes >= hashbytes) {
+ (void) putchar('#');
+ hashbytes += HASHBYTES;
+ }
+ (void) fflush(stdout);
+ }
+ }
+ if (hash && bytes > 0) {
+ if (bytes < HASHBYTES)
+ (void) putchar('#');
+ (void) putchar('\n');
+ (void) fflush(stdout);
+ }
+ if (c < 0)
+ fprintf(stderr, "local: %s: %s\n", local,
+ strerror(errno));
+ if (d < 0 || (d = secure_flush(fileno(dout))) < 0) {
+ if (d == -1 && errno != EPIPE)
+ perror("netout");
+ bytes = -1;
+ }
+ break;
+
+ case TYPE_A:
+ while ((c = getc(fin)) != EOF) {
+ if (c == '\n') {
+ while (hash && (bytes >= hashbytes)) {
+ (void) putchar('#');
+ (void) fflush(stdout);
+ hashbytes += HASHBYTES;
+ }
+ if (ferror(dout) ||
+ secure_putc('\r', dout) < 0)
+ break;
+ bytes++;
+ }
+ if (secure_putc(c, dout) < 0)
+ break;
+ bytes++;
+ /* if (c == '\r') { */
+ /* (void) putc('\0', dout); /* this violates rfc */
+ /* bytes++; */
+ /* } */
+ }
+ if (hash) {
+ if (bytes < hashbytes)
+ (void) putchar('#');
+ (void) putchar('\n');
+ (void) fflush(stdout);
+ }
+ if (ferror(fin))
+ fprintf(stderr, "local: %s: %s\n", local,
+ strerror(errno));
+ d = 0;
+ if (ferror(dout) || (d = secure_flush(fileno(dout))) < 0) {
+ if ((ferror(dout) || d == -1) && errno != EPIPE)
+ perror("netout");
+ bytes = -1;
+ }
+ break;
+ }
+ (void) gettimeofday(&stop, (struct timezone *)0);
+ if (closefunc != NULL)
+ (*closefunc)(fin);
+ (void) fclose(dout);
+ (void) getreply(0);
+ (void) signal(SIGINT, oldintr);
+ if (oldintp)
+ (void) signal(SIGPIPE, oldintp);
+ if (bytes > 0)
+ ptransfer("sent", bytes, &start, &stop);
+ return;
+abort:
+ (void) gettimeofday(&stop, (struct timezone *)0);
+ (void) signal(SIGINT, oldintr);
+ if (oldintp)
+ (void) signal(SIGPIPE, oldintp);
+ if (!cpend) {
+ code = -1;
+ return;
+ }
+ if (data >= 0) {
+ (void) close(data);
+ data = -1;
+ }
+ if (dout)
+ (void) fclose(dout);
+ (void) getreply(0);
+ code = -1;
+ if (closefunc != NULL && fin != NULL)
+ (*closefunc)(fin);
+ if (bytes > 0)
+ ptransfer("sent", bytes, &start, &stop);
+}
+
+jmp_buf recvabort;
+
+sigtype
+abortrecv(sig)
+ int sig;
+{
+
+ mflag = 0;
+ abrtflag = 0;
+ printf("\nreceive aborted\nwaiting for remote to finish abort\n");
+ (void) fflush(stdout);
+ longjmp(recvabort, 1);
+}
+
+recvrequest(cmd, local, remote, lmode, printnames)
+ char *cmd, *local, *remote, *lmode;
+{
+ FILE *fout, *din = 0, *popen();
+ int (*closefunc)(), pclose(), fclose();
+ sig_t oldintr, oldintp;
+ int is_retr, tcrflag, bare_lfs = 0;
+ char *gunique();
+ static int bufsize;
+ static char *buf;
+ int blksize;
+ long bytes = 0, hashbytes = HASHBYTES;
+ register int c, d;
+ struct timeval start, stop;
+ struct stat st;
+ off_t lseek();
+ sigtype abortrecv();
+
+ is_retr = strcmp(cmd, "RETR") == 0;
+ if (is_retr && verbose && printnames) {
+ if (local && *local != '-')
+ printf("local: %s ", local);
+ if (remote)
+ printf("remote: %s\n", remote);
+ }
+ if (proxy && is_retr) {
+ proxtrans(cmd, local, remote);
+ return;
+ }
+ closefunc = NULL;
+ oldintr = NULL;
+ oldintp = NULL;
+ tcrflag = !crflag && is_retr;
+ if (setjmp(recvabort)) {
+ while (cpend) {
+ (void) getreply(0);
+ }
+ if (data >= 0) {
+ (void) close(data);
+ data = -1;
+ }
+ if (oldintr)
+ (void) signal(SIGINT, oldintr);
+ code = -1;
+ return;
+ }
+ oldintr = signal(SIGINT, abortrecv);
+ if (strcmp(local, "-") && *local != '|') {
+ if (access(local, 2) < 0) {
+ char *dir = strrchr(local, '/');
+
+ if (errno != ENOENT && errno != EACCES) {
+ fprintf(stderr, "local: %s: %s\n", local,
+ strerror(errno));
+ (void) signal(SIGINT, oldintr);
+ code = -1;
+ return;
+ }
+ if (dir != NULL)
+ *dir = 0;
+ d = access(dir ? local : ".", 2);
+ if (dir != NULL)
+ *dir = '/';
+ if (d < 0) {
+ fprintf(stderr, "local: %s: %s\n", local,
+ strerror(errno));
+ (void) signal(SIGINT, oldintr);
+ code = -1;
+ return;
+ }
+ if (!runique && errno == EACCES &&
+ chmod(local, 0600) < 0) {
+ fprintf(stderr, "local: %s: %s\n", local,
+ strerror(errno));
+ (void) signal(SIGINT, oldintr);
+ (void) signal(SIGINT, oldintr);
+ code = -1;
+ return;
+ }
+ if (runique && errno == EACCES &&
+ (local = gunique(local)) == NULL) {
+ (void) signal(SIGINT, oldintr);
+ code = -1;
+ return;
+ }
+ }
+ else if (runique && (local = gunique(local)) == NULL) {
+ (void) signal(SIGINT, oldintr);
+ code = -1;
+ return;
+ }
+ }
+ if (!is_retr) {
+ if (curtype != TYPE_A)
+ changetype(TYPE_A, 0);
+ } else if (curtype != type)
+ changetype(type, 0);
+ if (initconn()) {
+ (void) signal(SIGINT, oldintr);
+ code = -1;
+ return;
+ }
+ if (setjmp(recvabort))
+ goto abort;
+ if (is_retr && restart_point &&
+ command("REST %ld", (long) restart_point) != CONTINUE)
+ return;
+ if (remote) {
+ if (command("%s %s", cmd, remote) != PRELIM) {
+ (void) signal(SIGINT, oldintr);
+ return;
+ }
+ } else {
+ if (command("%s", cmd) != PRELIM) {
+ (void) signal(SIGINT, oldintr);
+ return;
+ }
+ }
+ din = dataconn("r");
+ if (din == NULL)
+ goto abort;
+ if (strcmp(local, "-") == 0)
+ fout = stdout;
+ else if (*local == '|') {
+ oldintp = signal(SIGPIPE, SIG_IGN);
+ fout = popen(local + 1, "w");
+ if (fout == NULL) {
+ perror(local+1);
+ goto abort;
+ }
+ closefunc = pclose;
+ } else {
+ fout = fopen(local, lmode);
+ if (fout == NULL) {
+ fprintf(stderr, "local: %s: %s\n", local,
+ strerror(errno));
+ goto abort;
+ }
+ closefunc = fclose;
+ }
+ blksize = FTP_BUFSIZ;
+#ifndef NOSTBLKSIZE
+ if (fstat(fileno(fout), &st) == 0 && st.st_blksize != 0)
+ blksize = st.st_blksize;
+#endif
+ if (blksize > bufsize) {
+ if (buf)
+ (void) free(buf);
+ buf = (char *)malloc((unsigned)blksize);
+ if (buf == NULL) {
+ perror("malloc");
+ bufsize = 0;
+ goto abort;
+ }
+ bufsize = blksize;
+ }
+ (void) gettimeofday(&start, (struct timezone *)0);
+ switch (curtype) {
+
+ case TYPE_I:
+ case TYPE_L:
+ if (restart_point &&
+ lseek(fileno(fout), (long) restart_point, L_SET) < 0) {
+ fprintf(stderr, "local: %s: %s\n", local,
+ strerror(errno));
+ if (closefunc != NULL)
+ (*closefunc)(fout);
+ return;
+ }
+ errno = d = 0;
+ while ((c = secure_read(fileno(din), buf, bufsize)) > 0) {
+ if ((d = write(fileno(fout), buf, c)) != c)
+ break;
+ bytes += c;
+ if (hash) {
+ while (bytes >= hashbytes) {
+ (void) putchar('#');
+ hashbytes += HASHBYTES;
+ }
+ (void) fflush(stdout);
+ }
+ }
+ if (hash && bytes > 0) {
+ if (bytes < HASHBYTES)
+ (void) putchar('#');
+ (void) putchar('\n');
+ (void) fflush(stdout);
+ }
+ if (c < 0) {
+ if (c == -1 && errno != EPIPE)
+ perror("netin");
+ bytes = -1;
+ }
+ if (d < c) {
+ if (d < 0)
+ fprintf(stderr, "local: %s: %s\n", local,
+ strerror(errno));
+ else
+ fprintf(stderr, "%s: short write\n", local);
+ }
+ break;
+
+ case TYPE_A:
+ if (restart_point) {
+ register int i, n, ch;
+
+ if (fseek(fout, 0L, L_SET) < 0)
+ goto done;
+ n = restart_point;
+ for (i = 0; i++ < n;) {
+ if ((ch = getc(fout)) == EOF)
+ goto done;
+ if (ch == '\n')
+ i++;
+ }
+ if (fseek(fout, 0L, L_INCR) < 0) {
+done:
+ fprintf(stderr, "local: %s: %s\n", local,
+ strerror(errno));
+ if (closefunc != NULL)
+ (*closefunc)(fout);
+ return;
+ }
+ }
+ while ((c = secure_getc(din)) >= 0) {
+ if (c == '\n')
+ bare_lfs++;
+ while (c == '\r') {
+ while (hash && (bytes >= hashbytes)) {
+ (void) putchar('#');
+ (void) fflush(stdout);
+ hashbytes += HASHBYTES;
+ }
+ bytes++;
+ if ((c = secure_getc(din)) != '\n' || tcrflag) {
+ if (ferror(fout))
+ goto break2;
+ (void) putc('\r', fout);
+ if (c == '\0') {
+ bytes++;
+ goto contin2;
+ }
+ }
+ }
+ if (c < 0) break;
+ (void) putc(c, fout);
+ bytes++;
+ contin2: ;
+ }
+break2:
+ if (bare_lfs) {
+ printf("WARNING! %d bare linefeeds received in ASCII mode\n", bare_lfs);
+ printf("File may not have transferred correctly.\n");
+ }
+ if (hash) {
+ if (bytes < hashbytes)
+ (void) putchar('#');
+ (void) putchar('\n');
+ (void) fflush(stdout);
+ }
+ if (ferror(din)) {
+ if (errno != EPIPE)
+ perror("netin");
+ bytes = -1;
+ }
+ if (ferror(fout) || c == -2) {
+ if (c != -2)
+ fprintf(stderr, "local: %s: %s\n", local,
+ strerror(errno));
+ bytes = -1;
+ }
+ break;
+ }
+ if (closefunc != NULL)
+ (*closefunc)(fout);
+ (void) signal(SIGINT, oldintr);
+ if (oldintp)
+ (void) signal(SIGPIPE, oldintp);
+ (void) gettimeofday(&stop, (struct timezone *)0);
+ (void) fclose(din);
+ (void) getreply(0);
+ if (bytes > 0 && is_retr)
+ ptransfer("received", bytes, &start, &stop);
+ return;
+abort:
+
+/* abort using RFC959 recommended IP,SYNC sequence */
+
+ (void) gettimeofday(&stop, (struct timezone *)0);
+ if (oldintp)
+ (void) signal(SIGPIPE, oldintr);
+ (void) signal(SIGINT, SIG_IGN);
+ if (!cpend) {
+ code = -1;
+ (void) signal(SIGINT, oldintr);
+ return;
+ }
+
+ abort_remote(din);
+ code = -1;
+ if (data >= 0) {
+ (void) close(data);
+ data = -1;
+ }
+ if (closefunc != NULL && fout != NULL)
+ (*closefunc)(fout);
+ if (din)
+ (void) fclose(din);
+ if (bytes > 0)
+ ptransfer("received", bytes, &start, &stop);
+ (void) signal(SIGINT, oldintr);
+}
+
+/*
+ * Need to start a listen on the data channel before we send the command,
+ * otherwise the server's connect may fail.
+ */
+initconn()
+{
+ register char *p, *a;
+ int result, len, tmpno = 0;
+ int on = 1;
+#ifndef NO_PASSIVE_MODE
+ int a1,a2,a3,a4,p1,p2;
+
+ if (passivemode) {
+ data = socket(AF_INET, SOCK_STREAM, 0);
+ if (data < 0) {
+ perror("ftp: socket");
+ return(1);
+ }
+ if (options & SO_DEBUG &&
+ setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof (on)) < 0)
+ perror("ftp: setsockopt (ignored)");
+ if (command("PASV") != COMPLETE) {
+ printf("Passive mode refused. Turning off passive mode.\n");
+ passivemode = 0;
+ return initconn();
+ }
+
+/*
+ * What we've got at this point is a string of comma separated
+ * one-byte unsigned integer values, separated by commas.
+ * The first four are the an IP address. The fifth is the MSB
+ * of the port number, the sixth is the LSB. From that we'll
+ * prepare a sockaddr_in.
+ */
+
+ if (sscanf(pasv,"%d,%d,%d,%d,%d,%d",&a1,&a2,&a3,&a4,&p1,&p2) != 6) {
+ printf("Passive mode address scan failure. Shouldn't happen!\n");
+ return(1);
+ };
+
+ data_addr.sin_family = AF_INET;
+ data_addr.sin_addr.s_addr = htonl((a1<<24)|(a2<<16)|(a3<<8)|a4);
+ data_addr.sin_port = htons((p1<<8)|p2);
+
+ if (connect(data, (struct sockaddr *) &data_addr, sizeof(data_addr))<0) {
+ perror("ftp: connect");
+ return(1);
+ }
+#ifdef IP_TOS
+#ifdef IPTOS_THROUGHPUT
+ on = IPTOS_THROUGHPUT;
+ if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
+ perror("ftp: setsockopt TOS (ignored)");
+#endif
+#endif
+ hisdataaddr = data_addr;
+ return(0);
+ }
+#endif
+
+noport:
+ data_addr = myctladdr;
+ if (sendport)
+ data_addr.sin_port = 0; /* let system pick one */
+ if (data != -1)
+ (void) close(data);
+ data = socket(AF_INET, SOCK_STREAM, 0);
+ if (data < 0) {
+ perror("ftp: socket");
+ if (tmpno)
+ sendport = 1;
+ return (1);
+ }
+ if (!sendport)
+ if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)) < 0) {
+ perror("ftp: setsockopt (reuse address)");
+ goto bad;
+ }
+ if (bind(data, (struct sockaddr *)&data_addr, sizeof (data_addr)) < 0) {
+ perror("ftp: bind");
+ goto bad;
+ }
+ if (options & SO_DEBUG &&
+ setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof (on)) < 0)
+ perror("ftp: setsockopt (ignored)");
+ len = sizeof (data_addr);
+ if (getsockname(data, (struct sockaddr *)&data_addr, &len) < 0) {
+ perror("ftp: getsockname");
+ goto bad;
+ }
+ if (listen(data, 1) < 0)
+ perror("ftp: listen");
+ if (sendport) {
+ a = (char *)&data_addr.sin_addr;
+ p = (char *)&data_addr.sin_port;
+#define UC(b) (((int)b)&0xff)
+ result =
+ command("PORT %d,%d,%d,%d,%d,%d",
+ UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
+ UC(p[0]), UC(p[1]));
+ if (result == ERROR && sendport == -1) {
+ sendport = 0;
+ tmpno = 1;
+ goto noport;
+ }
+ return (result != COMPLETE);
+ }
+ if (tmpno)
+ sendport = 1;
+#ifdef IP_TOS
+#ifdef IPTOS_THROUGHPUT
+ on = IPTOS_THROUGHPUT;
+ if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
+ perror("ftp: setsockopt TOS (ignored)");
+#endif
+#endif
+ return (0);
+bad:
+ (void) close(data), data = -1;
+ if (tmpno)
+ sendport = 1;
+ return (1);
+}
+
+FILE *
+dataconn(lmode)
+ char *lmode;
+{
+ int s, fromlen = sizeof (hisdataaddr), tos;
+
+#ifndef NO_PASSIVE_MODE
+if (passivemode)
+ return (fdopen(data, lmode));
+#endif
+ s = accept(data, (struct sockaddr *) &hisdataaddr, &fromlen);
+ if (s < 0) {
+ perror("ftp: accept");
+ (void) close(data), data = -1;
+ return (NULL);
+ }
+ (void) close(data);
+ data = s;
+#ifdef IP_TOS
+#ifdef IPTOS_THROUGHPUT
+ tos = IPTOS_THROUGHPUT;
+ if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
+ perror("ftp: setsockopt TOS (ignored)");
+#endif
+#endif
+ return (fdopen(data, lmode));
+}
+
+ptransfer(direction, bytes, t0, t1)
+ char *direction;
+ long bytes;
+ struct timeval *t0, *t1;
+{
+ struct timeval td;
+ float s, kbs;
+
+ if (verbose) {
+ tvsub(&td, t1, t0);
+ s = td.tv_sec + (td.tv_usec / 1000000.);
+#define nz(x) ((x) == 0 ? 1 : (x))
+ kbs = (bytes / nz(s))/1024.0;
+ printf("%ld bytes %s in %.2g seconds (%.2g Kbytes/s)\n",
+ bytes, direction, s, kbs);
+ }
+}
+
+/*tvadd(tsum, t0)
+ struct timeval *tsum, *t0;
+{
+
+ tsum->tv_sec += t0->tv_sec;
+ tsum->tv_usec += t0->tv_usec;
+ if (tsum->tv_usec > 1000000)
+ tsum->tv_sec++, tsum->tv_usec -= 1000000;
+} */
+
+tvsub(tdiff, t1, t0)
+ struct timeval *tdiff, *t1, *t0;
+{
+
+ tdiff->tv_sec = t1->tv_sec - t0->tv_sec;
+ tdiff->tv_usec = t1->tv_usec - t0->tv_usec;
+ if (tdiff->tv_usec < 0)
+ tdiff->tv_sec--, tdiff->tv_usec += 1000000;
+}
+
+sigtype
+psabort(sig)
+ int sig;
+{
+ extern int abrtflag;
+
+ abrtflag++;
+}
+
+pswitch(flag)
+ int flag;
+{
+ extern int proxy, abrtflag;
+ sig_t oldintr;
+ static struct comvars {
+ int connect;
+ char name[MAXHOSTNAMELEN];
+ struct sockaddr_in mctl;
+ struct sockaddr_in hctl;
+ FILE *in;
+ FILE *out;
+ int tpe;
+ int curtpe;
+ int cpnd;
+ int sunqe;
+ int runqe;
+ int mcse;
+ int ntflg;
+ char nti[17];
+ char nto[17];
+ int mapflg;
+ char mi[MAXPATHLEN];
+ char mo[MAXPATHLEN];
+ char *authtype;
+ int lvl;
+#ifdef KERBEROS
+ C_Block session;
+ Key_schedule schedule;
+#endif /* KERBEROS */
+ } proxstruct, tmpstruct;
+ struct comvars *ip, *op;
+
+ abrtflag = 0;
+ oldintr = signal(SIGINT, psabort);
+ if (flag) {
+ if (proxy)
+ return;
+ ip = &tmpstruct;
+ op = &proxstruct;
+ proxy++;
+ } else {
+ if (!proxy)
+ return;
+ ip = &proxstruct;
+ op = &tmpstruct;
+ proxy = 0;
+ }
+ ip->connect = connected;
+ connected = op->connect;
+ if (hostname) {
+ (void) strncpy(ip->name, hostname, sizeof(ip->name) - 1);
+ ip->name[strlen(ip->name)] = '\0';
+ } else
+ ip->name[0] = 0;
+ hostname = op->name;
+ ip->hctl = hisctladdr;
+ hisctladdr = op->hctl;
+ ip->mctl = myctladdr;
+ myctladdr = op->mctl;
+ ip->in = cin;
+ cin = op->in;
+ ip->out = cout;
+ cout = op->out;
+ ip->tpe = type;
+ type = op->tpe;
+ ip->curtpe = curtype;
+ curtype = op->curtpe;
+ ip->cpnd = cpend;
+ cpend = op->cpnd;
+ ip->sunqe = sunique;
+ sunique = op->sunqe;
+ ip->runqe = runique;
+ runique = op->runqe;
+ ip->mcse = mcase;
+ mcase = op->mcse;
+ ip->ntflg = ntflag;
+ ntflag = op->ntflg;
+ (void) strncpy(ip->nti, ntin, 16);
+ (ip->nti)[strlen(ip->nti)] = '\0';
+ (void) strcpy(ntin, op->nti);
+ (void) strncpy(ip->nto, ntout, 16);
+ (ip->nto)[strlen(ip->nto)] = '\0';
+ (void) strcpy(ntout, op->nto);
+ ip->mapflg = mapflag;
+ mapflag = op->mapflg;
+ (void) strncpy(ip->mi, mapin, MAXPATHLEN - 1);
+ (ip->mi)[strlen(ip->mi)] = '\0';
+ (void) strcpy(mapin, op->mi);
+ (void) strncpy(ip->mo, mapout, MAXPATHLEN - 1);
+ (ip->mo)[strlen(ip->mo)] = '\0';
+ (void) strcpy(mapout, op->mo);
+ ip->authtype = auth_type;
+ auth_type = op->authtype;
+ ip->lvl = level;
+ level = op->lvl;
+ if (!level)
+ level = 1;
+#ifdef KERBEROS
+ memcpy(ip->session, cred.session, sizeof(cred.session));
+ memcpy(cred.session, op->session, sizeof(cred.session));
+ memcpy(ip->schedule, schedule, sizeof(schedule));
+ memcpy(schedule, op->schedule, sizeof(schedule));
+#endif /* KERBEROS */
+ (void) signal(SIGINT, oldintr);
+ if (abrtflag) {
+ abrtflag = 0;
+ (*oldintr)(SIGINT);
+ }
+}
+
+jmp_buf ptabort;
+int ptabflg;
+
+sigtype
+abortpt(sig)
+ int sig;
+{
+ printf("\n");
+ (void) fflush(stdout);
+ ptabflg++;
+ mflag = 0;
+ abrtflag = 0;
+ longjmp(ptabort, 1);
+}
+
+proxtrans(cmd, local, remote)
+ char *cmd, *local, *remote;
+{
+ sig_t oldintr;
+ int secndflag = 0, prox_type, nfnd;
+ extern jmp_buf ptabort;
+ char *cmd2;
+ struct fd_set mask;
+ sigtype abortpt();
+
+ if (strcmp(cmd, "RETR"))
+ cmd2 = "RETR";
+ else
+ cmd2 = runique ? "STOU" : "STOR";
+ if ((prox_type = type) == 0) {
+ if (unix_server && unix_proxy)
+ prox_type = TYPE_I;
+ else
+ prox_type = TYPE_A;
+ }
+ if (curtype != prox_type)
+ changetype(prox_type, 1);
+ if (command("PASV") != COMPLETE) {
+ printf("proxy server does not support third party transfers.\n");
+ return;
+ }
+ pswitch(0);
+ if (!connected) {
+ printf("No primary connection\n");
+ pswitch(1);
+ code = -1;
+ return;
+ }
+ if (curtype != prox_type)
+ changetype(prox_type, 1);
+ if (command("PORT %s", pasv) != COMPLETE) {
+ pswitch(1);
+ return;
+ }
+ if (setjmp(ptabort))
+ goto abort;
+ oldintr = signal(SIGINT, abortpt);
+ if (command("%s %s", cmd, remote) != PRELIM) {
+ (void) signal(SIGINT, oldintr);
+ pswitch(1);
+ return;
+ }
+ sleep(2);
+ pswitch(1);
+ secndflag++;
+ if (command("%s %s", cmd2, local) != PRELIM)
+ goto abort;
+ ptflag++;
+ (void) getreply(0);
+ pswitch(0);
+ (void) getreply(0);
+ (void) signal(SIGINT, oldintr);
+ pswitch(1);
+ ptflag = 0;
+ printf("local: %s remote: %s\n", local, remote);
+ return;
+abort:
+ (void) signal(SIGINT, SIG_IGN);
+ ptflag = 0;
+ if (strcmp(cmd, "RETR") && !proxy)
+ pswitch(1);
+ else if (!strcmp(cmd, "RETR") && proxy)
+ pswitch(0);
+ if (!cpend && !secndflag) { /* only here if cmd = "STOR" (proxy=1) */
+ if (command("%s %s", cmd2, local) != PRELIM) {
+ pswitch(0);
+ if (cpend)
+ abort_remote((FILE *) NULL);
+ }
+ pswitch(1);
+ if (ptabflg)
+ code = -1;
+ (void) signal(SIGINT, oldintr);
+ return;
+ }
+ if (cpend)
+ abort_remote((FILE *) NULL);
+ pswitch(!proxy);
+ if (!cpend && !secndflag) { /* only if cmd = "RETR" (proxy=1) */
+ if (command("%s %s", cmd2, local) != PRELIM) {
+ pswitch(0);
+ if (cpend)
+ abort_remote((FILE *) NULL);
+ pswitch(1);
+ if (ptabflg)
+ code = -1;
+ (void) signal(SIGINT, oldintr);
+ return;
+ }
+ }
+ if (cpend)
+ abort_remote((FILE *) NULL);
+ pswitch(!proxy);
+ if (cpend) {
+ FD_ZERO(&mask);
+ FD_SET(fileno(cin), &mask);
+ if ((nfnd = empty(&mask, 10)) <= 0) {
+ if (nfnd < 0) {
+ perror("abort");
+ }
+ if (ptabflg)
+ code = -1;
+ lostpeer();
+ }
+ (void) getreply(0);
+ (void) getreply(0);
+ }
+ if (proxy)
+ pswitch(0);
+ pswitch(1);
+ if (ptabflg)
+ code = -1;
+ (void) signal(SIGINT, oldintr);
+}
+
+reset()
+{
+ struct fd_set mask;
+ int nfnd = 1;
+
+ FD_ZERO(&mask);
+ while (nfnd > 0) {
+ FD_SET(fileno(cin), &mask);
+ if ((nfnd = empty(&mask,0)) < 0) {
+ perror("reset");
+ code = -1;
+ lostpeer();
+ }
+ else if (nfnd) {
+ (void) getreply(0);
+ }
+ }
+}
+
+char *
+gunique(local)
+ char *local;
+{
+ static char new[MAXPATHLEN];
+ char *cp = strrchr(local, '/');
+ int d, count=0;
+ char ext = '1';
+
+ if (cp)
+ *cp = '\0';
+ d = access(cp ? local : ".", 2);
+ if (cp)
+ *cp = '/';
+ if (d < 0) {
+ fprintf(stderr, "local: %s: %s\n", local, strerror(errno));
+ return((char *) 0);
+ }
+ (void) strcpy(new, local);
+ cp = new + strlen(new);
+ *cp++ = '.';
+ while (!d) {
+ if (++count == 100) {
+ printf("runique: can't find unique file name.\n");
+ return((char *) 0);
+ }
+ *cp++ = ext;
+ *cp = '\0';
+ if (ext == '9')
+ ext = '0';
+ else
+ ext++;
+ if ((d = access(new, 0)) < 0)
+ break;
+ if (ext != '0')
+ cp--;
+ else if (*(cp - 2) == '.')
+ *(cp - 1) = '1';
+ else {
+ *(cp - 2) = *(cp - 2) + 1;
+ cp--;
+ }
+ }
+ return(new);
+}
+
+#ifdef KERBEROS
+char realm[REALM_SZ + 1];
+#endif /* KERBEROS */
+
+#ifdef GSSAPI
+/* for testing, we don't have an ftp key yet */
+char* gss_services[] = { /* "ftp",*/ "host", 0 };
+#endif /* GSSAPI */
+
+do_auth()
+{
+ extern int setsafe();
+ int oldverbose;
+#ifdef KERBEROS
+ char *service, inst[INST_SZ];
+ u_long cksum, checksum = (u_long) getpid();
+#endif /* KERBEROS */
+#if defined(KERBEROS) || defined(GSSAPI)
+ u_char out_buf[FTP_BUFSIZ];
+ int i;
+#endif /* KERBEROS */
+
+ if (auth_type) return(1); /* auth already succeeded */
+
+ /* Other auth types go here ... */
+
+#ifdef KERBEROS
+ if (command("AUTH %s", "KERBEROS_V4") == CONTINUE) {
+ if (verbose)
+ printf("%s accepted as authentication type\n", "KERBEROS_V4");
+
+ strcpy(inst, (char *) krb_get_phost(hostname));
+ if (realm[0] == '\0')
+ strcpy(realm, (char *) krb_realmofhost(hostname));
+ if ((kerror = krb_mk_req(&ticket, service = "ftp",
+ inst, realm, checksum))
+ && (kerror != KDC_PR_UNKNOWN ||
+ (kerror = krb_mk_req(&ticket, service = "rcmd",
+ inst, realm, checksum))))
+ fprintf(stderr, "Kerberos V4 krb_mk_req failed: %s\n",
+ krb_get_err_text(kerror));
+ else if (kerror = krb_get_cred(service, inst, realm, &cred))
+ fprintf(stderr, "Kerberos V4 krb_get_cred failed: %s\n",
+ krb_get_err_text(kerror));
+ else {
+ key_sched(cred.session, schedule);
+ reply_parse = "ADAT=";
+ oldverbose = verbose;
+ verbose = 0;
+ i = ticket.length;
+ if (kerror = radix_encode(ticket.dat, out_buf, &i, 0))
+ fprintf(stderr, "Base 64 encoding failed: %s\n",
+ radix_error(kerror));
+ else if (command("ADAT %s", out_buf) != COMPLETE)
+ fprintf(stderr, "Kerberos V4 authentication failed\n");
+ else if (!reply_parse)
+ fprintf(stderr,
+ "No authentication data received from server\n");
+ else if (kerror = radix_encode(reply_parse, out_buf, &i, 1))
+ fprintf(stderr, "Base 64 decoding failed: %s\n",
+ radix_error(kerror));
+ else if (kerror = krb_rd_safe(out_buf, i, &cred.session,
+ &hisctladdr, &myctladdr, &msg_data))
+ fprintf(stderr, "Kerberos V4 krb_rd_safe failed: %s\n",
+ krb_get_err_text(kerror));
+ else {
+ /* fetch the (modified) checksum */
+ (void) memcpy(&cksum, msg_data.app_data, sizeof(cksum));
+ if (ntohl(cksum) == checksum + 1) {
+ verbose = oldverbose;
+ if (verbose)
+ printf("Kerberos V4 authentication succeeded\n");
+ reply_parse = NULL;
+ auth_type = "KERBEROS_V4";
+ return(1);
+ } else fprintf(stderr,
+ "Kerberos V4 mutual authentication failed\n");
+ }
+ verbose = oldverbose;
+ reply_parse = NULL;
+ }
+ } else fprintf(stderr, "%s rejected as an authentication type\n",
+ "KERBEROS_V4");
+#endif /* KERBEROS */
+#ifdef GSSAPI
+ if (command("AUTH %s", "GSSAPI") == CONTINUE) {
+ OM_uint32 maj_stat, min_stat;
+ gss_name_t target_name;
+ gss_buffer_desc send_tok, recv_tok, *token_ptr;
+ char stbuf[FTP_BUFSIZ];
+ char **service_name, **end_service_name;
+ int comcode;
+ struct gss_channel_bindings_struct chan;
+ chan.initiator_addrtype = GSS_C_AF_INET; /* OM_uint32 */
+ chan.initiator_address.length = 4;
+ chan.initiator_address.value = &myctladdr.sin_addr.s_addr;
+ chan.acceptor_addrtype = GSS_C_AF_INET; /* OM_uint32 */
+ chan.acceptor_address.length = 4;
+ chan.acceptor_address.value = &hisctladdr.sin_addr.s_addr;
+ chan.application_data.length = 0;
+ chan.application_data.value = 0;
+
+ for (end_service_name = gss_services; *end_service_name; )
+ end_service_name++;
+ end_service_name--;
+
+ if (verbose)
+ printf("%s accepted as authentication type\n", "GSSAPI");
+
+ /* blob from gss-client */
+
+
+ for (service_name = gss_services; *service_name; service_name++) {
+
+ /* ftp@hostname first, the host@hostname */
+ /* the V5 GSSAPI binding canonicalizes this for us... */
+ sprintf(stbuf, "%s@%s", *service_name, hostname);
+ if (debug)
+ fprintf(stderr, "Trying to authenticate to <%s>\n", stbuf);
+
+ send_tok.value = stbuf;
+ send_tok.length = strlen(stbuf) + 1;
+ maj_stat = gss_import_name(&min_stat, &send_tok,
+ gss_nt_service_name, &target_name);
+
+ if (maj_stat != GSS_S_COMPLETE) {
+ user_gss_error(maj_stat, min_stat, "parsing name");
+ secure_error("name parsed <%s>\n", stbuf);
+ continue;
+ }
+
+ token_ptr = GSS_C_NO_BUFFER;
+ gcontext = GSS_C_NO_CONTEXT; /* structure copy */
+
+ do {
+ if (debug)
+ fprintf(stderr, "calling gss_init_sec_context\n");
+ maj_stat =
+ gss_init_sec_context(&min_stat,
+ GSS_C_NO_CREDENTIAL,
+ &gcontext,
+ target_name,
+ GSS_C_NULL_OID,
+ GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG,
+ 0,
+ &chan, /* channel bindings */
+ token_ptr,
+ NULL, /* ignore mech type */
+ &send_tok,
+ NULL, /* ignore ret_flags */
+ NULL); /* ignore time_rec */
+
+
+ if (maj_stat!=GSS_S_COMPLETE && maj_stat!=GSS_S_CONTINUE_NEEDED){
+ user_gss_error(maj_stat, min_stat, "initializing context");
+ (void) gss_release_name(&min_stat, &target_name);
+ /* could just be that we missed on the service name */
+ goto outer_loop;
+ }
+
+ if (send_tok.length != 0) {
+ int len = send_tok.length;
+ reply_parse = "ADAT="; /* for command() later */
+ oldverbose = verbose;
+ verbose = 0;
+ kerror = radix_encode(send_tok.value, out_buf, &len, 0);
+ if (kerror) {
+ fprintf(stderr, "Base 64 encoding failed: %s\n",
+ radix_error(kerror));
+ } else if ((comcode = command("ADAT %s", out_buf))!=COMPLETE
+ /* && comcode != 3 (335)*/) {
+ fprintf(stderr, "GSSAPI ADAT failed\n");
+ /* force out of loop */
+ maj_stat = GSS_S_FAILURE;
+ } else if (!reply_parse) {
+ fprintf(stderr,
+ "No authentication data received from server\n");
+ if (maj_stat == GSS_S_COMPLETE) {
+ fprintf(stderr, "...but no more was needed\n");
+ goto gss_complete_loop;
+ } else {
+ user_gss_error(maj_stat, min_stat, "no reply, huh?");
+ goto gss_complete_loop;
+ }
+ } else if (kerror = radix_encode(reply_parse,out_buf,&i,1)) {
+ fprintf(stderr, "Base 64 decoding failed: %s\n",
+ radix_error(kerror));
+ } else {
+ /* everything worked */
+ token_ptr = &recv_tok;
+ recv_tok.value = out_buf;
+ recv_tok.length = i;
+ continue;
+ }
+
+ /* get out of loop clean */
+ gss_complete_loop:
+ service_name = end_service_name;
+ gss_release_buffer(&min_stat, &send_tok);
+ gss_release_name(&min_stat, &target_name);
+ goto outer_loop;
+ }
+ } while (maj_stat == GSS_S_CONTINUE_NEEDED);
+ outer_loop:
+ ;
+ }
+ verbose = oldverbose;
+ if (maj_stat == GSS_S_COMPLETE) {
+ if (verbose)
+ printf("GSSAPI authentication succeeded\n");
+ reply_parse = NULL;
+ auth_type = "GSSAPI";
+ return(1);
+ } else {
+ fprintf(stderr, "GSSAPI authentication failed\n");
+ verbose = oldverbose;
+ reply_parse = NULL;
+ }
+ }
+#endif /* GSSAPI */
+
+ /* Other auth types go here ... */
+
+ return(0);
+}
+
+setpbsz(size)
+unsigned int size;
+{
+ int oldverbose;
+
+ if (ucbuf) (void) free(ucbuf);
+ actualbuf = size;
+ while ((ucbuf = (unsigned char *)malloc(actualbuf)) == NULL)
+ if (actualbuf)
+ actualbuf >>= 2;
+ else {
+ perror("Error while trying to malloc PROT buffer:");
+ exit(1);
+ }
+ oldverbose = verbose;
+ verbose = 0;
+ reply_parse = "PBSZ=";
+ if (command("PBSZ %u", actualbuf) != COMPLETE)
+ fatal("Cannot set PROT buffer size");
+ if (reply_parse) {
+ if ((maxbuf = (unsigned int) atol(reply_parse)) > actualbuf)
+ maxbuf = actualbuf;
+ } else maxbuf = actualbuf;
+ reply_parse = NULL;
+ verbose = oldverbose;
+}
+
+abort_remote(din)
+FILE *din;
+{
+ char buf[FTP_BUFSIZ];
+ int nfnd;
+ struct fd_set mask;
+
+ /*
+ * send IAC in urgent mode instead of DM because 4.3BSD places oob mark
+ * after urgent byte rather than before as is protocol now
+ */
+ sprintf(buf, "%c%c%c", IAC, IP, IAC);
+ if (send(fileno(cout), buf, 3, MSG_OOB) != 3)
+ perror("abort");
+ putc(DM, cout);
+ (void) secure_command("ABOR");
+ FD_ZERO(&mask);
+ FD_SET(fileno(cin), &mask);
+ if (din) {
+ FD_SET(fileno(din), &mask);
+ }
+ if ((nfnd = empty(&mask, 10)) <= 0) {
+ if (nfnd < 0) {
+ perror("abort");
+ }
+ if (ptabflg)
+ code = -1;
+ lostpeer();
+ }
+ if (din && FD_ISSET(fileno(din), &mask)) {
+ /* Security: No threat associated with this read. */
+ while (read(fileno(din), buf, FTP_BUFSIZ) > 0)
+ /* LOOP */;
+ }
+ if (getreply(0) == ERROR && code == 552) {
+ /* 552 needed for nic style abort */
+ (void) getreply(0);
+ }
+ (void) getreply(0);
+}
+#ifdef GSSAPI
+user_gss_error(maj_stat, min_stat, s)
+OM_uint32 maj_stat, min_stat;
+char *s;
+{
+ /* a lot of work just to report the error */
+ OM_uint32 gmaj_stat, gmin_stat;
+ gss_buffer_desc msg;
+ int msg_ctx;
+ msg_ctx = 0;
+ while (!msg_ctx) {
+ gmaj_stat = gss_display_status(&gmin_stat, maj_stat,
+ GSS_C_GSS_CODE,
+ GSS_C_NULL_OID,
+ &msg_ctx, &msg);
+ if ((gmaj_stat == GSS_S_COMPLETE)||
+ (gmaj_stat == GSS_S_CONTINUE_NEEDED)) {
+ fprintf(stderr, "GSSAPI error major: %s\n",
+ (char*)msg.value);
+ (void) gss_release_buffer(&gmin_stat, &msg);
+ }
+ if (gmaj_stat != GSS_S_CONTINUE_NEEDED)
+ break;
+ }
+ msg_ctx = 0;
+ while (!msg_ctx) {
+ gmaj_stat = gss_display_status(&gmin_stat, min_stat,
+ GSS_C_MECH_CODE,
+ GSS_C_NULL_OID,
+ &msg_ctx, &msg);
+ if ((gmaj_stat == GSS_S_COMPLETE)||
+ (gmaj_stat == GSS_S_CONTINUE_NEEDED)) {
+ fprintf(stderr, "GSSAPI error minor: %s\n",
+ (char*)msg.value);
+ (void) gss_release_buffer(&gmin_stat, &msg);
+ }
+ if (gmaj_stat != GSS_S_CONTINUE_NEEDED)
+ break;
+ }
+ fprintf(stderr, "GSSAPI error: %s\n", s);
+}
+
+secure_gss_error(maj_stat, min_stat, s)
+ OM_uint32 maj_stat, min_stat;
+ char *s;
+{
+ return user_gss_error(maj_stat, min_stat, s);
+}
+#endif /* GSSAPI */
diff --git a/src/appl/gssftp/ftp/ftp_var.h b/src/appl/gssftp/ftp/ftp_var.h
new file mode 100644
index 0000000..afc7d36
--- /dev/null
+++ b/src/appl/gssftp/ftp/ftp_var.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 1985, 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)ftp_var.h 5.9 (Berkeley) 6/1/90
+ */
+
+/*
+ * FTP global variables.
+ */
+
+#ifdef DEFINITIONS
+#define extern
+#endif
+
+/*
+ * Options and other state info.
+ */
+extern int trace; /* trace packets exchanged */
+extern int hash; /* print # for each buffer transferred */
+extern int sendport; /* use PORT cmd for each data connection */
+extern int verbose; /* print messages coming back from server */
+extern int connected; /* connected to server */
+extern int fromatty; /* input is from a terminal */
+extern int interactive; /* interactively prompt on m* cmds */
+extern int debug; /* debugging level */
+extern int bell; /* ring bell on cmd completion */
+extern int doglob; /* glob local file names */
+extern int autologin; /* establish user account on connection */
+extern int proxy; /* proxy server connection active */
+extern int proxflag; /* proxy connection exists */
+extern int sunique; /* store files on server with unique name */
+extern int runique; /* store local files with unique name */
+extern int mcase; /* map upper to lower case for mget names */
+extern int ntflag; /* use ntin ntout tables for name translation */
+extern int mapflag; /* use mapin mapout templates on file names */
+extern int code; /* return/reply code for ftp command */
+extern int crflag; /* if 1, strip car. rets. on ascii gets */
+extern char pasv[64]; /* passive port for proxy data connection */
+#ifndef NO_PASSIVE_MODE
+extern int passivemode; /* passive mode enabled */
+#endif
+extern char *altarg; /* argv[1] with no shell-like preprocessing */
+extern char ntin[17]; /* input translation table */
+extern char ntout[17]; /* output translation table */
+#include <sys/param.h>
+extern char mapin[MAXPATHLEN]; /* input map template */
+extern char mapout[MAXPATHLEN]; /* output map template */
+extern int level; /* protection level */
+extern int type; /* requested file transfer type */
+extern int curtype; /* current file transfer type */
+extern int stru; /* file transfer structure */
+extern int form; /* file transfer format */
+extern int mode; /* file transfer mode */
+extern char bytename[32]; /* local byte size in ascii */
+extern int bytesize; /* local byte size in binary */
+
+extern char *hostname; /* name of host connected to */
+extern int unix_server; /* server is unix, can use binary for ascii */
+extern int unix_proxy; /* proxy is unix, can use binary for ascii */
+
+extern struct servent *sp; /* service spec for tcp/ftp */
+
+#include <setjmp.h>
+extern jmp_buf toplevel; /* non-local goto stuff for cmd scanner */
+
+extern char line[200]; /* input line buffer */
+extern char *stringbase; /* current scan point in line buffer */
+extern char argbuf[200]; /* argument storage buffer */
+extern char *argbase; /* current storage point in arg buffer */
+extern int margc; /* count of arguments on input line */
+extern char *margv[20]; /* args parsed from input line */
+extern int cpend; /* flag: if != 0, then pending server reply */
+extern int mflag; /* flag: if != 0, then active multi command */
+
+extern int options; /* used during socket creation */
+
+/*
+ * Format of command table.
+ */
+struct cmd {
+ char *c_name; /* name of command */
+ char *c_help; /* help string */
+ char c_bell; /* give bell when command completes */
+ char c_conn; /* must be connected to use command */
+ char c_proxy; /* proxy server may execute */
+ int (*c_handler)(); /* function to call */
+};
+
+struct macel {
+ char mac_name[9]; /* macro name */
+ char *mac_start; /* start of macro in macbuf */
+ char *mac_end; /* end of macro in macbuf */
+};
+
+extern int macnum; /* number of defined macros */
+extern struct macel macros[16];
+extern char macbuf[4096];
+
+#ifdef DEFINITIONS
+#undef extern
+#endif
+
+extern char *tail();
+extern char *remglob();
+extern int errno;
+extern char *mktemp();
+
+#if defined(STDARG) || (defined(__STDC__) && ! defined(VARARGS))
+extern command(char *, ...);
+#endif
diff --git a/src/appl/gssftp/ftp/getpass.c b/src/appl/gssftp/ftp/getpass.c
new file mode 100644
index 0000000..9020373
--- /dev/null
+++ b/src/appl/gssftp/ftp/getpass.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 1985 Regents of the University of California.
+ * All rights reserved. The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)getpass.c 1.1 90/04/28 SMI"; /* from UCB 5.4 3/7/86 */
+#endif /* not lint */
+
+#include <stdio.h>
+#include <signal.h>
+
+#if defined (POSIX) || defined (POSIX_TERMIOS)
+#include <termios.h>
+static struct termios ttyo, ttyb;
+#define stty(f, t) tcsetattr(f, TCSANOW, t)
+#define gtty(f, t) tcgetattr(f, t)
+#else
+#include <sgtty.h>
+static struct sgttyb ttyo, ttyb;
+#endif
+
+static FILE *fi;
+
+#define sig_t my_sig_t
+#define sigtype krb5_sigtype
+typedef sigtype (*sig_t)();
+
+static sigtype
+intfix(sig)
+ int sig;
+{
+ if (fi != NULL)
+ (void) stty(fileno(fi), &ttyo);
+ exit(SIGINT);
+}
+
+char *
+mygetpass(prompt)
+char *prompt;
+{
+ register char *p;
+ register c;
+ static char pbuf[50+1];
+ sigtype (*sig)();
+
+ if ((fi = fopen("/dev/tty", "r")) == NULL)
+ fi = stdin;
+ else
+ setbuf(fi, (char *)NULL);
+ sig = signal(SIGINT, intfix);
+ (void) gtty(fileno(fi), &ttyb);
+ ttyo = ttyb;
+#if defined (POSIX) || defined (POSIX_TERMIOS)
+ ttyb.c_lflag &= ~ECHO;
+#else
+ ttyb.sg_flags &= ~ECHO;
+#endif
+ (void) stty(fileno(fi), &ttyb);
+ fprintf(stderr, "%s", prompt); (void) fflush(stderr);
+ for (p=pbuf; (c = getc(fi))!='\n' && c!=EOF;) {
+ if (p < &pbuf[sizeof(pbuf)-1])
+ *p++ = c;
+ }
+ *p = '\0';
+ fprintf(stderr, "\n"); (void) fflush(stderr);
+ (void) stty(fileno(fi), &ttyo);
+ (void) signal(SIGINT, sig);
+ if (fi != stdin)
+ (void) fclose(fi);
+ return(pbuf);
+}
diff --git a/src/appl/gssftp/ftp/glob.c b/src/appl/gssftp/ftp/glob.c
new file mode 100644
index 0000000..3a793d8
--- /dev/null
+++ b/src/appl/gssftp/ftp/glob.c
@@ -0,0 +1,698 @@
+/*
+ * Copyright (c) 1980 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)glob.c 5.9 (Berkeley) 2/25/91";
+#endif /* not lint */
+
+/*
+ * C-shell glob for random programs.
+ */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <dirent.h>
+
+#include <pwd.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef POSIX
+#include <limits.h>
+#endif
+
+#ifdef ARG_MAX
+#undef NCARGS
+#define NCARGS ARG_MAX
+#endif
+
+#ifndef NCARGS
+#define NCARGS 4096
+#endif
+
+#define QUOTE 0200
+#define TRIM 0177
+#define eq(a,b) (strcmp(a, b)==0)
+#define GAVSIZ (NCARGS/6)
+#define isdir(d) ((d.st_mode & S_IFMT) == S_IFDIR)
+
+static char **gargv; /* Pointer to the (stack) arglist */
+static int gargc; /* Number args in gargv */
+static int gnleft;
+static short gflag;
+static int tglob();
+char **ftpglob();
+char *globerr;
+char *home;
+extern int errno;
+static char *strspl(), *strend();
+char **copyblk();
+
+static void acollect(), addpath(), collect(), expand(), Gcat();
+static void ginit(), matchdir(), rscan(), sort();
+static int amatch(), execbrc(), match();
+
+static int globcnt;
+
+char *globchars = "`{[*?";
+
+static char *gpath, *gpathp, *lastgpathp;
+static int globbed;
+static char *entp;
+static char **sortbas;
+
+char **
+ftpglob(v)
+ register char *v;
+{
+ char agpath[FTP_BUFSIZ];
+ char *agargv[GAVSIZ];
+ char *vv[2];
+ vv[0] = v;
+ vv[1] = 0;
+ gflag = 0;
+ rscan(vv, tglob);
+ if (gflag == 0)
+ return (copyblk(vv));
+
+ globerr = 0;
+ gpath = agpath; gpathp = gpath; *gpathp = 0;
+ lastgpathp = &gpath[sizeof agpath - 2];
+ ginit(agargv); globcnt = 0;
+ collect(v);
+ if (globcnt == 0 && (gflag&1)) {
+ blkfree(gargv), gargv = 0;
+ return (0);
+ } else
+ return (gargv = copyblk(gargv));
+}
+
+static void
+ginit(agargv)
+ char **agargv;
+{
+
+ agargv[0] = 0; gargv = agargv; sortbas = agargv; gargc = 0;
+ gnleft = NCARGS - 4;
+}
+
+static void
+collect(as)
+ register char *as;
+{
+ if (eq(as, "{") || eq(as, "{}")) {
+ Gcat(as, "");
+ sort();
+ } else
+ acollect(as);
+}
+
+static void
+acollect(as)
+ register char *as;
+{
+ register int ogargc = gargc;
+
+ gpathp = gpath; *gpathp = 0; globbed = 0;
+ expand(as);
+ if (gargc != ogargc)
+ sort();
+}
+
+static void
+sort()
+{
+ register char **p1, **p2, *c;
+ char **Gvp = &gargv[gargc];
+
+ p1 = sortbas;
+ while (p1 < Gvp-1) {
+ p2 = p1;
+ while (++p2 < Gvp)
+ if (strcmp(*p1, *p2) > 0)
+ c = *p1, *p1 = *p2, *p2 = c;
+ p1++;
+ }
+ sortbas = Gvp;
+}
+
+static void
+expand(as)
+ char *as;
+{
+ register char *cs;
+ register char *sgpathp, *oldcs;
+ struct stat stb;
+
+ sgpathp = gpathp;
+ cs = as;
+ if (*cs == '~' && gpathp == gpath) {
+ addpath('~');
+ for (cs++; letter(*cs) || digit(*cs) || *cs == '-';)
+ addpath(*cs++);
+ if (!*cs || *cs == '/') {
+ if (gpathp != gpath + 1) {
+ *gpathp = 0;
+ if (gethdir(gpath + 1))
+ globerr = "Unknown user name after ~";
+ (void) strcpy(gpath, gpath + 1);
+ } else
+ (void) strcpy(gpath, home);
+ gpathp = strend(gpath);
+ }
+ }
+ while (!any(*cs, globchars)) {
+ if (*cs == 0) {
+ if (!globbed)
+ Gcat(gpath, "");
+ else if (stat(gpath, &stb) >= 0) {
+ Gcat(gpath, "");
+ globcnt++;
+ }
+ goto endit;
+ }
+ addpath(*cs++);
+ }
+ oldcs = cs;
+ while (cs > as && *cs != '/')
+ cs--, gpathp--;
+ if (*cs == '/')
+ cs++, gpathp++;
+ *gpathp = 0;
+ if (*oldcs == '{') {
+ (void) execbrc(cs, ((char *)0));
+ return;
+ }
+ matchdir(cs);
+endit:
+ gpathp = sgpathp;
+ *gpathp = 0;
+}
+
+static void
+matchdir(pattern)
+ char *pattern;
+{
+ struct stat stb;
+ register struct dirent *dp;
+ DIR *dirp;
+
+ dirp = opendir(*gpath?gpath:".");
+ if (dirp == NULL) {
+ if (globbed)
+ return;
+ goto patherr2;
+ }
+ /* This fails on systems where you can't inspect the contents of
+ the DIR structure. If there are systems whose opendir does
+ not check for a directory, then use stat, not fstat. */
+#if 0
+ if (fstat(dirp->dd_fd, &stb) < 0)
+ goto patherr1;
+ if (!isdir(stb)) {
+ errno = ENOTDIR;
+ goto patherr1;
+ }
+#endif
+ while ((dp = readdir(dirp)) != NULL) {
+ if (dp->d_ino == 0)
+ continue;
+ if (match(dp->d_name, pattern)) {
+ Gcat(gpath, dp->d_name);
+ globcnt++;
+ }
+ }
+ closedir(dirp);
+ return;
+
+patherr1:
+ closedir(dirp);
+patherr2:
+ globerr = "Bad directory components";
+}
+
+static int
+execbrc(p, s)
+ char *p, *s;
+{
+ char restbuf[FTP_BUFSIZ + 2];
+ register char *pe, *pm, *pl;
+ int brclev = 0;
+ char *lm, savec, *sgpathp;
+
+ for (lm = restbuf; *p != '{'; *lm++ = *p++)
+ continue;
+ for (pe = ++p; *pe; pe++)
+ switch (*pe) {
+
+ case '{':
+ brclev++;
+ continue;
+
+ case '}':
+ if (brclev == 0)
+ goto pend;
+ brclev--;
+ continue;
+
+ case '[':
+ for (pe++; *pe && *pe != ']'; pe++)
+ continue;
+ continue;
+ }
+pend:
+ brclev = 0;
+ for (pl = pm = p; pm <= pe; pm++)
+ switch (*pm & (QUOTE|TRIM)) {
+
+ case '{':
+ brclev++;
+ continue;
+
+ case '}':
+ if (brclev) {
+ brclev--;
+ continue;
+ }
+ goto doit;
+
+ case ','|QUOTE:
+ case ',':
+ if (brclev)
+ continue;
+doit:
+ savec = *pm;
+ *pm = 0;
+ (void) strcpy(lm, pl);
+ (void) strcat(restbuf, pe + 1);
+ *pm = savec;
+ if (s == 0) {
+ sgpathp = gpathp;
+ expand(restbuf);
+ gpathp = sgpathp;
+ *gpathp = 0;
+ } else if (amatch(s, restbuf))
+ return (1);
+ sort();
+ pl = pm + 1;
+ if (brclev)
+ return (0);
+ continue;
+
+ case '[':
+ for (pm++; *pm && *pm != ']'; pm++)
+ continue;
+ if (!*pm)
+ pm--;
+ continue;
+ }
+ if (brclev)
+ goto doit;
+ return (0);
+}
+
+static int
+match(s, p)
+ char *s, *p;
+{
+ register int c;
+ register char *sentp;
+ char sglobbed = globbed;
+
+ if (*s == '.' && *p != '.')
+ return (0);
+ sentp = entp;
+ entp = s;
+ c = amatch(s, p);
+ entp = sentp;
+ globbed = sglobbed;
+ return (c);
+}
+
+static int
+amatch(s, p)
+ register char *s, *p;
+{
+ register int scc;
+ int ok, lc;
+ char *sgpathp;
+ struct stat stb;
+ int c, cc;
+
+ globbed = 1;
+ for (;;) {
+ scc = *s++ & TRIM;
+ switch (c = *p++) {
+
+ case '{':
+ return (execbrc(p - 1, s - 1));
+
+ case '[':
+ ok = 0;
+ lc = 077777;
+ while (cc = *p++) {
+ if (cc == ']') {
+ if (ok)
+ break;
+ return (0);
+ }
+ if (cc == '-') {
+ if (lc <= scc && scc <= *p++)
+ ok++;
+ } else
+ if (scc == (lc = cc))
+ ok++;
+ }
+ if (cc == 0)
+ if (ok)
+ p--;
+ else
+ return 0;
+ continue;
+
+ case '*':
+ if (!*p)
+ return (1);
+ if (*p == '/') {
+ p++;
+ goto slash;
+ }
+ s--;
+ do {
+ if (amatch(s, p))
+ return (1);
+ } while (*s++);
+ return (0);
+
+ case 0:
+ return (scc == 0);
+
+ default:
+ if (c != scc)
+ return (0);
+ continue;
+
+ case '?':
+ if (scc == 0)
+ return (0);
+ continue;
+
+ case '/':
+ if (scc)
+ return (0);
+slash:
+ s = entp;
+ sgpathp = gpathp;
+ while (*s)
+ addpath(*s++);
+ addpath('/');
+ if (stat(gpath, &stb) == 0 && isdir(stb))
+ if (*p == 0) {
+ Gcat(gpath, "");
+ globcnt++;
+ } else
+ expand(p);
+ gpathp = sgpathp;
+ *gpathp = 0;
+ return (0);
+ }
+ }
+}
+
+static
+Gmatch(s, p)
+ register char *s, *p;
+{
+ register int scc;
+ int ok, lc;
+ int c, cc;
+
+ for (;;) {
+ scc = *s++ & TRIM;
+ switch (c = *p++) {
+
+ case '[':
+ ok = 0;
+ lc = 077777;
+ while (cc = *p++) {
+ if (cc == ']') {
+ if (ok)
+ break;
+ return (0);
+ }
+ if (cc == '-') {
+ if (lc <= scc && scc <= *p++)
+ ok++;
+ } else
+ if (scc == (lc = cc))
+ ok++;
+ }
+ if (cc == 0)
+ if (ok)
+ p--;
+ else
+ return 0;
+ continue;
+
+ case '*':
+ if (!*p)
+ return (1);
+ for (s--; *s; s++)
+ if (Gmatch(s, p))
+ return (1);
+ return (0);
+
+ case 0:
+ return (scc == 0);
+
+ default:
+ if ((c & TRIM) != scc)
+ return (0);
+ continue;
+
+ case '?':
+ if (scc == 0)
+ return (0);
+ continue;
+
+ }
+ }
+}
+
+static void
+Gcat(s1, s2)
+ register char *s1, *s2;
+{
+ register int len = strlen(s1) + strlen(s2) + 1;
+
+ if (len >= gnleft || gargc >= GAVSIZ - 1)
+ globerr = "Arguments too long";
+ else {
+ gargc++;
+ gnleft -= len;
+ gargv[gargc] = 0;
+ gargv[gargc - 1] = strspl(s1, s2);
+ }
+}
+
+static void
+addpath(c)
+ char c;
+{
+
+ if (gpathp >= lastgpathp)
+ globerr = "Pathname too long";
+ else {
+ *gpathp++ = c;
+ *gpathp = 0;
+ }
+}
+
+static void
+rscan(t, f)
+ register char **t;
+ int (*f)();
+{
+ register char *p, c;
+
+ while (p = *t++) {
+ if (f == tglob)
+ if (*p == '~')
+ gflag |= 2;
+ else if (eq(p, "{") || eq(p, "{}"))
+ continue;
+ while (c = *p++)
+ (*f)(c);
+ }
+}
+/*
+static
+scan(t, f)
+ register char **t;
+ int (*f)();
+{
+ register char *p, c;
+
+ while (p = *t++)
+ while (c = *p)
+ *p++ = (*f)(c);
+} */
+
+static
+tglob(c)
+ register char c;
+{
+
+ if (any(c, globchars))
+ gflag |= c == '{' ? 2 : 1;
+ return (c);
+}
+/*
+static
+trim(c)
+ char c;
+{
+
+ return (c & TRIM);
+} */
+
+
+letter(c)
+ register char c;
+{
+
+ return (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '_');
+}
+
+digit(c)
+ register char c;
+{
+
+ return (c >= '0' && c <= '9');
+}
+
+any(c, s)
+ register int c;
+ register char *s;
+{
+
+ while (*s)
+ if (*s++ == c)
+ return(1);
+ return(0);
+}
+blklen(av)
+ register char **av;
+{
+ register int i = 0;
+
+ while (*av++)
+ i++;
+ return (i);
+}
+
+char **
+blkcpy(oav, bv)
+ char **oav;
+ register char **bv;
+{
+ register char **av = oav;
+
+ while (*av++ = *bv++)
+ continue;
+ return (oav);
+}
+
+blkfree(av0)
+ char **av0;
+{
+ register char **av = av0;
+
+ while (*av)
+ free(*av++);
+}
+
+static
+char *
+strspl(cp, dp)
+ register char *cp, *dp;
+{
+ register char *ep = malloc((unsigned)(strlen(cp) + strlen(dp) + 1));
+
+ if (ep == (char *)0)
+ fatal("Out of memory");
+ (void) strcpy(ep, cp);
+ (void) strcat(ep, dp);
+ return (ep);
+}
+
+char **
+copyblk(v)
+ register char **v;
+{
+ register char **nv = (char **)malloc((unsigned)((blklen(v) + 1) *
+ sizeof(char **)));
+ if (nv == (char **)0)
+ fatal("Out of memory");
+
+ return (blkcpy(nv, v));
+}
+
+static
+char *
+strend(cp)
+ register char *cp;
+{
+
+ while (*cp)
+ cp++;
+ return (cp);
+}
+/*
+ * Extract a home directory from the password file
+ * The argument points to a buffer where the name of the
+ * user whose home directory is sought is currently.
+ * We write the home directory of the user back there.
+ */
+gethdir(home)
+ char *home;
+{
+ register struct passwd *pp = getpwnam(home);
+
+ if (!pp || home + strlen(pp->pw_dir) >= lastgpathp)
+ return (1);
+ (void) strcpy(home, pp->pw_dir);
+ return (0);
+}
diff --git a/src/appl/gssftp/ftp/main.c b/src/appl/gssftp/ftp/main.c
new file mode 100644
index 0000000..4a6d88f
--- /dev/null
+++ b/src/appl/gssftp/ftp/main.c
@@ -0,0 +1,553 @@
+/*
+ * Copyright (c) 1985, 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1985, 1989 Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)main.c 5.18 (Berkeley) 3/1/91";
+#endif /* not lint */
+
+/*
+ * FTP User Program -- Command Interface.
+ */
+#include <stdio.h>
+#include "ftp_var.h"
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+
+#include <arpa/ftp.h>
+
+#include <signal.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <netdb.h>
+#include <pwd.h>
+
+#define sig_t my_sig_t
+#define sigtype krb5_sigtype
+typedef sigtype (*sig_t)();
+
+uid_t getuid();
+sigtype intr(), lostpeer();
+extern char *home;
+char *getlogin();
+#ifdef KERBEROS
+#include <krb.h>
+struct servent staticsp;
+extern char realm[];
+#endif /* KERBEROS */
+
+main(argc, argv)
+ char *argv[];
+{
+ register char *cp;
+ int top;
+ struct passwd *pw = NULL;
+ char homedir[MAXPATHLEN];
+
+ sp = getservbyname("ftp", "tcp");
+ if (sp == 0) {
+ fprintf(stderr, "ftp: ftp/tcp: unknown service\n");
+ exit(1);
+ }
+#ifdef KERBEROS
+/* GDM need to static sp so that the information is not lost
+ when kerberos calls getservbyname */
+ memcpy(&staticsp,sp,sizeof(struct servent));
+ sp = &staticsp;
+#endif /* KERBEROS */
+ doglob = 1;
+ interactive = 1;
+ autologin = 1;
+ argc--, argv++;
+ while (argc > 0 && **argv == '-') {
+ for (cp = *argv + 1; *cp; cp++)
+ switch (*cp) {
+
+ case 'd':
+ options |= SO_DEBUG;
+ debug++;
+ break;
+
+#ifdef KERBEROS
+ case 'k':
+ if (*++cp != '\0')
+ strncpy(realm, ++cp, REALM_SZ);
+ else if (argc > 1) {
+ argc--, argv++;
+ strncpy(realm, *argv, REALM_SZ);
+ }
+ else
+ fprintf(stderr, "ftp: -k expects arguments\n");
+ goto nextopt;
+#endif
+
+ case 'v':
+ verbose++;
+ break;
+
+ case 't':
+ trace++;
+ break;
+
+ case 'i':
+ interactive = 0;
+ break;
+
+ case 'n':
+ autologin = 0;
+ break;
+
+ case 'g':
+ doglob = 0;
+ break;
+
+ default:
+ fprintf(stdout,
+ "ftp: %c: unknown option\n", *cp);
+ exit(1);
+ }
+ nextopt:
+ argc--, argv++;
+ }
+ fromatty = isatty(fileno(stdin));
+ if (fromatty)
+ verbose++;
+ cpend = 0; /* no pending replies */
+ proxy = 0; /* proxy not active */
+#ifndef NO_PASSIVE_MODE
+ passivemode = 1; /* passive mode active */
+#endif
+ crflag = 1; /* strip c.r. on ascii gets */
+ sendport = -1; /* not using ports */
+ /*
+ * Set up the home directory in case we're globbing.
+ */
+ cp = getlogin();
+ if (cp != NULL) {
+ pw = getpwnam(cp);
+ }
+ if (pw == NULL)
+ pw = getpwuid(getuid());
+ if (pw != NULL) {
+ home = homedir;
+ (void) strcpy(home, pw->pw_dir);
+ }
+ if (argc > 0) {
+ if (setjmp(toplevel))
+ exit(0);
+ (void) signal(SIGINT, intr);
+ (void) signal(SIGPIPE, lostpeer);
+ setpeer(argc + 1, argv - 1);
+ }
+ top = setjmp(toplevel) == 0;
+ if (top) {
+ (void) signal(SIGINT, intr);
+ (void) signal(SIGPIPE, lostpeer);
+ }
+ for (;;) {
+ cmdscanner(top);
+ top = 1;
+ }
+}
+
+sigtype
+intr(sig)
+ int sig;
+{
+
+ longjmp(toplevel, 1);
+}
+
+sigtype
+lostpeer(sig)
+ int sig;
+{
+ extern FILE *cout;
+ extern int data;
+ extern char *auth_type;
+ extern int level;
+
+ if (connected) {
+ if (cout != NULL) {
+ (void) shutdown(fileno(cout), 1+1);
+ (void) fclose(cout);
+ cout = NULL;
+ }
+ if (data >= 0) {
+ (void) shutdown(data, 1+1);
+ (void) close(data);
+ data = -1;
+ }
+ connected = 0;
+ auth_type = NULL;
+ level = PROT_C;
+ }
+ pswitch(1);
+ if (connected) {
+ if (cout != NULL) {
+ (void) shutdown(fileno(cout), 1+1);
+ (void) fclose(cout);
+ cout = NULL;
+ }
+ connected = 0;
+ auth_type = NULL;
+ level = PROT_C;
+ }
+ proxflag = 0;
+ pswitch(0);
+}
+
+/*char *
+tail(filename)
+ char *filename;
+{
+ register char *s;
+
+ while (*filename) {
+ s = strrchr(filename, '/');
+ if (s == NULL)
+ break;
+ if (s[1])
+ return (s + 1);
+ *s = '\0';
+ }
+ return (filename);
+}
+*/
+/*
+ * Command parser.
+ */
+cmdscanner(top)
+ int top;
+{
+ register struct cmd *c;
+ register int l;
+ struct cmd *getcmd();
+ extern int help();
+
+ if (!top)
+ (void) putchar('\n');
+ for (;;) {
+ if (fromatty) {
+ printf("ftp> ");
+ (void) fflush(stdout);
+ }
+ if (fgets(line, sizeof line, stdin) == NULL)
+ quit();
+ l = strlen(line);
+ if (l == 0)
+ break;
+ if (line[--l] == '\n') {
+ if (l == 0)
+ break;
+ line[l] = '\0';
+ } else if (l == sizeof(line) - 2) {
+ printf("sorry, input line too long\n");
+ while ((l = getchar()) != '\n' && l != EOF)
+ /* void */;
+ break;
+ } /* else it was a line without a newline */
+ makeargv();
+ if (margc == 0) {
+ continue;
+ }
+ c = getcmd(margv[0]);
+ if (c == (struct cmd *)-1) {
+ printf("?Ambiguous command\n");
+ continue;
+ }
+ if (c == 0) {
+ printf("?Invalid command\n");
+ continue;
+ }
+ if (c->c_conn && !connected) {
+ printf("Not connected.\n");
+ continue;
+ }
+ (*c->c_handler)(margc, margv);
+ if (bell && c->c_bell)
+ (void) putchar('\007');
+ if (c->c_handler != help)
+ break;
+ }
+ (void) signal(SIGINT, intr);
+ (void) signal(SIGPIPE, lostpeer);
+}
+
+struct cmd *
+getcmd(name)
+ register char *name;
+{
+ extern struct cmd cmdtab[];
+ register char *p, *q;
+ register struct cmd *c, *found;
+ register int nmatches, longest;
+
+ longest = 0;
+ nmatches = 0;
+ found = 0;
+ for (c = cmdtab; p = c->c_name; c++) {
+ for (q = name; *q == *p++; q++)
+ if (*q == 0) /* exact match? */
+ return (c);
+ if (!*q) { /* the name was a prefix */
+ if (q - name > longest) {
+ longest = q - name;
+ nmatches = 1;
+ found = c;
+ } else if (q - name == longest)
+ nmatches++;
+ }
+ }
+ if (nmatches > 1)
+ return ((struct cmd *)-1);
+ return (found);
+}
+
+/*
+ * Slice a string up into argc/argv.
+ */
+
+int slrflag;
+
+makeargv()
+{
+ char **argp;
+ char *slurpstring();
+
+ margc = 0;
+ argp = margv;
+ stringbase = line; /* scan from first of buffer */
+ argbase = argbuf; /* store from first of buffer */
+ slrflag = 0;
+ while (*argp++ = slurpstring())
+ margc++;
+}
+
+/*
+ * Parse string into argbuf;
+ * implemented with FSM to
+ * handle quoting and strings
+ */
+char *
+slurpstring()
+{
+ int got_one = 0;
+ register char *sb = stringbase;
+ register char *ap = argbase;
+ char *tmp = argbase; /* will return this if token found */
+
+ if (*sb == '!' || *sb == '$') { /* recognize ! as a token for shell */
+ switch (slrflag) { /* and $ as token for macro invoke */
+ case 0:
+ slrflag++;
+ stringbase++;
+ return ((*sb == '!') ? "!" : "$");
+ /* NOTREACHED */
+ case 1:
+ slrflag++;
+ altarg = stringbase;
+ break;
+ default:
+ break;
+ }
+ }
+
+S0:
+ switch (*sb) {
+
+ case '\0':
+ goto OUT;
+
+ case ' ':
+ case '\t':
+ sb++; goto S0;
+
+ default:
+ switch (slrflag) {
+ case 0:
+ slrflag++;
+ break;
+ case 1:
+ slrflag++;
+ altarg = sb;
+ break;
+ default:
+ break;
+ }
+ goto S1;
+ }
+
+S1:
+ switch (*sb) {
+
+ case ' ':
+ case '\t':
+ case '\0':
+ goto OUT; /* end of token */
+
+ case '\\':
+ sb++; goto S2; /* slurp next character */
+
+ case '"':
+ sb++; goto S3; /* slurp quoted string */
+
+ default:
+ *ap++ = *sb++; /* add character to token */
+ got_one = 1;
+ goto S1;
+ }
+
+S2:
+ switch (*sb) {
+
+ case '\0':
+ goto OUT;
+
+ default:
+ *ap++ = *sb++;
+ got_one = 1;
+ goto S1;
+ }
+
+S3:
+ switch (*sb) {
+
+ case '\0':
+ goto OUT;
+
+ case '"':
+ sb++; goto S1;
+
+ default:
+ *ap++ = *sb++;
+ got_one = 1;
+ goto S3;
+ }
+
+OUT:
+ if (got_one)
+ *ap++ = '\0';
+ argbase = ap; /* update storage pointer */
+ stringbase = sb; /* update scan pointer */
+ if (got_one) {
+ return(tmp);
+ }
+ switch (slrflag) {
+ case 0:
+ slrflag++;
+ break;
+ case 1:
+ slrflag++;
+ altarg = (char *) 0;
+ break;
+ default:
+ break;
+ }
+ return((char *)0);
+}
+
+#define HELPINDENT (sizeof ("directory"))
+
+/*
+ * Help command.
+ * Call each command handler with argc == 0 and argv[0] == name.
+ */
+help(argc, argv)
+ int argc;
+ char *argv[];
+{
+ extern struct cmd cmdtab[];
+ register struct cmd *c;
+
+ if (argc == 1) {
+ register int i, j, w, k;
+ int columns, width = 0, lines;
+ extern int NCMDS;
+
+ printf("Commands may be abbreviated. Commands are:\n\n");
+ for (c = cmdtab; c < &cmdtab[NCMDS]; c++) {
+ int len = strlen(c->c_name);
+
+ if (len > width)
+ width = len;
+ }
+ width = (width + 8) &~ 7;
+ columns = 80 / width;
+ if (columns == 0)
+ columns = 1;
+ lines = (NCMDS + columns - 1) / columns;
+ for (i = 0; i < lines; i++) {
+ for (j = 0; j < columns; j++) {
+ c = cmdtab + j * lines + i;
+ if (c->c_name && (!proxy || c->c_proxy)) {
+ printf("%s", c->c_name);
+ }
+ else if (c->c_name) {
+ for (k=0; k < strlen(c->c_name); k++) {
+ (void) putchar(' ');
+ }
+ }
+ if (c + lines >= &cmdtab[NCMDS]) {
+ printf("\n");
+ break;
+ }
+ w = strlen(c->c_name);
+ while (w < width) {
+ w = (w + 8) &~ 7;
+ (void) putchar('\t');
+ }
+ }
+ }
+ return;
+ }
+ while (--argc > 0) {
+ register char *arg;
+ arg = *++argv;
+ c = getcmd(arg);
+ if (c == (struct cmd *)-1)
+ printf("?Ambiguous help command %s\n", arg);
+ else if (c == (struct cmd *)0)
+ printf("?Invalid help command %s\n", arg);
+ else
+ printf("%-*s\t%s\n", HELPINDENT,
+ c->c_name, c->c_help);
+ }
+}
diff --git a/src/appl/gssftp/ftp/pathnames.h b/src/appl/gssftp/ftp/pathnames.h
new file mode 100644
index 0000000..7c0de5b
--- /dev/null
+++ b/src/appl/gssftp/ftp/pathnames.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)pathnames.h 5.2 (Berkeley) 6/1/90
+ */
+
+#undef _PATH_TMP
+#define _PATH_TMP "/tmp/ftpXXXXXX"
diff --git a/src/appl/gssftp/ftp/pclose.c b/src/appl/gssftp/ftp/pclose.c
new file mode 100644
index 0000000..e1e13e4
--- /dev/null
+++ b/src/appl/gssftp/ftp/pclose.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 1980 Regents of the University of California.
+ * All rights reserved. The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)pclose.c 1.1 90/04/28 SMI"; /* from UCB 1.2 3/7/86 */
+#endif /* not lint */
+
+#include <stdio.h>
+#include <signal.h>
+#include <sys/param.h>
+#include <sys/wait.h>
+#ifdef HAVE_VFORK_H
+#include <vfork.h>
+#endif
+#define sig_t my_sig_t
+#define sigtype krb5_sigtype
+typedef sigtype (*sig_t)();
+
+#define tst(a,b) (*mode == 'r'? (b) : (a))
+#define RDR 0
+#define WTR 1
+
+static int *popen_pid;
+static int nfiles;
+
+#ifndef HAVE_GETDTABLESIZE
+#include <sys/resource.h>
+int getdtablesize() {
+ struct rlimit rl;
+ getrlimit(RLIMIT_NOFILE, &rl);
+ return rl.rlim_cur;
+}
+#endif
+
+FILE *
+mypopen(cmd,mode)
+ char *cmd;
+ char *mode;
+{
+ int p[2];
+ int myside, hisside, pid;
+
+ if (nfiles <= 0)
+ nfiles = getdtablesize();
+ if (popen_pid == NULL) {
+ popen_pid = (int *)malloc((unsigned) nfiles * sizeof *popen_pid);
+ if (popen_pid == NULL)
+ return (NULL);
+ for (pid = 0; pid < nfiles; pid++)
+ popen_pid[pid] = -1;
+ }
+ if (pipe(p) < 0)
+ return (NULL);
+ myside = tst(p[WTR], p[RDR]);
+ hisside = tst(p[RDR], p[WTR]);
+ if ((pid = vfork()) == 0) {
+ /* myside and hisside reverse roles in child */
+ (void) close(myside);
+ if (hisside != tst(0, 1)) {
+ (void) dup2(hisside, tst(0, 1));
+ (void) close(hisside);
+ }
+ execl("/bin/sh", "sh", "-c", cmd, (char *)NULL);
+ _exit(127);
+ }
+ if (pid == -1) {
+ (void) close(myside);
+ (void) close(hisside);
+ return (NULL);
+ }
+ popen_pid[myside] = pid;
+ (void) close(hisside);
+ return (fdopen(myside, mode));
+}
+
+sigtype
+pabort(sig)
+ int sig;
+{
+ extern int mflag;
+
+ mflag = 0;
+}
+
+mypclose(ptr)
+ FILE *ptr;
+{
+ int child, pid;
+#ifdef USE_SIGPROCMASK
+ sigset_t old, new;
+#else
+ int omask;
+#endif
+ sigtype pabort(), (*istat)();
+#ifdef WAIT_USES_INT
+ int status;
+#else
+ union wait status;
+#endif
+
+ child = popen_pid[fileno(ptr)];
+ popen_pid[fileno(ptr)] = -1;
+ (void) fclose(ptr);
+ if (child == -1)
+ return (-1);
+ istat = signal(SIGINT, pabort);
+#ifdef USE_SIGPROCMASK
+ sigemptyset(&old);
+ sigemptyset(&new);
+ sigaddset(&new,SIGQUIT);
+ sigaddset(&new,SIGHUP);
+ sigprocmask(SIG_BLOCK, &new, &old);
+ while ((pid = wait(&status)) != child && pid != -1)
+ ;
+ sigprocmask(SIG_SETMASK, &old, NULL);
+#else
+ omask = sigblock(sigmask(SIGQUIT)|sigmask(SIGHUP));
+ while ((pid = wait(&status)) != child && pid != -1)
+ ;
+ sigsetmask(omask);
+#endif
+ (void) signal(SIGINT, istat);
+ return (pid == -1 ? -1 : 0);
+}
diff --git a/src/appl/gssftp/ftp/radix.c b/src/appl/gssftp/ftp/radix.c
new file mode 100644
index 0000000..c651ef5
--- /dev/null
+++ b/src/appl/gssftp/ftp/radix.c
@@ -0,0 +1,163 @@
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+
+static char *radixN =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+static char pad = '=';
+
+radix_encode(inbuf, outbuf, len, decode)
+unsigned char inbuf[], outbuf[];
+int *len, decode;
+{
+ int i,j,D;
+ char *p;
+ unsigned char c;
+
+ if (decode) {
+ for (i=0,j=0; inbuf[i] && inbuf[i] != pad; i++) {
+ if ((p = strchr(radixN, inbuf[i])) == NULL) return(1);
+ D = p - radixN;
+ switch (i&3) {
+ case 0:
+ outbuf[j] = D<<2;
+ break;
+ case 1:
+ outbuf[j++] |= D>>4;
+ outbuf[j] = (D&15)<<4;
+ break;
+ case 2:
+ outbuf[j++] |= D>>2;
+ outbuf[j] = (D&3)<<6;
+ break;
+ case 3:
+ outbuf[j++] |= D;
+ }
+ }
+ switch (i&3) {
+ case 1: return(3);
+ case 2: if (D&15) return(3);
+ if (strcmp((char *)&inbuf[i], "==")) return(2);
+ break;
+ case 3: if (D&3) return(3);
+ if (strcmp((char *)&inbuf[i], "=")) return(2);
+ }
+ *len = j;
+ } else {
+ for (i=0,j=0; i < *len; i++)
+ switch (i%3) {
+ case 0:
+ outbuf[j++] = radixN[inbuf[i]>>2];
+ c = (inbuf[i]&3)<<4;
+ break;
+ case 1:
+ outbuf[j++] = radixN[c|inbuf[i]>>4];
+ c = (inbuf[i]&15)<<2;
+ break;
+ case 2:
+ outbuf[j++] = radixN[c|inbuf[i]>>6];
+ outbuf[j++] = radixN[inbuf[i]&63];
+ c = 0;
+ }
+ if (i%3) outbuf[j++] = radixN[c];
+ switch (i%3) {
+ case 1: outbuf[j++] = pad;
+ case 2: outbuf[j++] = pad;
+ }
+ outbuf[*len = j] = '\0';
+ }
+ return(0);
+}
+
+char *
+radix_error(e)
+{
+ switch (e) {
+ case 0: return("Success");
+ case 1: return("Bad character in encoding");
+ case 2: return("Encoding not properly padded");
+ case 3: return("Decoded # of bits not a multiple of 8");
+ default: return("Unknown error");
+ }
+}
+
+#ifdef STANDALONE
+usage(s)
+char *s;
+{
+ fprintf(stderr, "Usage: %s [ -d ] [ string ]\n", s);
+ exit(2);
+}
+
+static int n;
+
+putbuf(inbuf, outbuf, len, decode)
+unsigned char inbuf[], outbuf[];
+int len, decode;
+{
+ int c;
+
+ if (c = radix_encode(inbuf, outbuf, &len, decode)) {
+ fprintf(stderr, "Couldn't %scode input: %s\n",
+ decode ? "de" : "en", radix_error(c));
+ exit(1);
+ }
+ if (decode)
+ write(1, outbuf, len);
+ else
+ for (c = 0; c < len;) {
+ putchar(outbuf[c++]);
+ if (++n%76 == 0) putchar('\n');
+ }
+}
+
+main(argc,argv)
+int argc;
+char *argv[];
+{
+ unsigned char *inbuf, *outbuf;
+ int c, len = 0, decode = 0;
+ extern int optind;
+
+ while ((c = getopt(argc, argv, "d")) != EOF)
+ switch(c) {
+ default:
+ usage(argv[0]);
+ case 'd':
+ decode++;
+ }
+
+ switch (argc - optind) {
+ case 0:
+ inbuf = (unsigned char *) malloc(5);
+ outbuf = (unsigned char *) malloc(5);
+ while ((c = getchar()) != EOF)
+ if (c != '\n') {
+ inbuf[len++] = c;
+ if (len == (decode ? 4 : 3)) {
+ inbuf[len] = '\0';
+ putbuf(inbuf, outbuf, len, decode);
+ len=0;
+ }
+ }
+ if (len) {
+ inbuf[len] = '\0';
+ putbuf(inbuf, outbuf, len, decode);
+ }
+ break;
+ case 1:
+ inbuf = (unsigned char *)argv[optind];
+ len = strlen(inbuf);
+ outbuf = (unsigned char *)
+ malloc((len * (decode?3:4)) / (decode?4:3) + 1);
+ putbuf(inbuf, outbuf, len, decode);
+ break;
+ default:
+ fprintf(stderr, "Only one argument allowed\n");
+ usage(argv[0]);
+ }
+ if (n%76) putchar('\n');
+ exit(0);
+}
+#endif /* STANDALONE */
diff --git a/src/appl/gssftp/ftp/ruserpass.c b/src/appl/gssftp/ftp/ruserpass.c
new file mode 100644
index 0000000..5587c6c
--- /dev/null
+++ b/src/appl/gssftp/ftp/ruserpass.c
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 1985 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ruserpass.c 5.3 (Berkeley) 3/1/91";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#ifdef POSIX
+#include <stdlib.h>
+#endif
+#include <ctype.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include "ftp_var.h"
+
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 64
+#endif
+
+char *renvlook(), *getenv();
+static FILE *cfile;
+
+#define DEFAULT 1
+#define LOGIN 2
+#define PASSWD 3
+#define ACCOUNT 4
+#define MACDEF 5
+#define ID 10
+#define MACH 11
+
+static char tokval[100];
+
+static struct toktab {
+ char *tokstr;
+ int tval;
+} toktab[]= {
+ "default", DEFAULT,
+ "login", LOGIN,
+ "password", PASSWD,
+ "passwd", PASSWD,
+ "account", ACCOUNT,
+ "machine", MACH,
+ "macdef", MACDEF,
+ 0, 0
+};
+
+
+static
+token()
+{
+ char *cp;
+ int c;
+ struct toktab *t;
+
+ if (feof(cfile))
+ return (0);
+ while ((c = getc(cfile)) != EOF &&
+ (c == '\n' || c == '\t' || c == ' ' || c == ','))
+ continue;
+ if (c == EOF)
+ return (0);
+ cp = tokval;
+ if (c == '"') {
+ while ((c = getc(cfile)) != EOF && c != '"') {
+ if (c == '\\')
+ c = getc(cfile);
+ *cp++ = c;
+ }
+ } else {
+ *cp++ = c;
+ while ((c = getc(cfile)) != EOF
+ && c != '\n' && c != '\t' && c != ' ' && c != ',') {
+ if (c == '\\')
+ c = getc(cfile);
+ *cp++ = c;
+ }
+ }
+ *cp = 0;
+ if (tokval[0] == 0)
+ return (0);
+ for (t = toktab; t->tokstr; t++)
+ if (!strcmp(t->tokstr, tokval))
+ return (t->tval);
+ return (ID);
+}
+
+ruserpass(host, aname, apass, aacct)
+ char *host, **aname, **apass, **aacct;
+{
+ char *hdir, buf[FTP_BUFSIZ], *tmp;
+ char myname[MAXHOSTNAMELEN], *mydomain;
+ int t, i, c, usedefault = 0;
+ struct stat stb;
+
+ hdir = getenv("HOME");
+ if (hdir == NULL)
+ hdir = ".";
+ (void) sprintf(buf, "%s/.netrc", hdir);
+ cfile = fopen(buf, "r");
+ if (cfile == NULL) {
+ if (errno != ENOENT)
+ perror(buf);
+ return(0);
+ }
+ if (gethostname(myname, sizeof(myname)) < 0)
+ myname[0] = '\0';
+ if ((mydomain = strchr(myname, '.')) == NULL)
+ mydomain = "";
+next:
+ while ((t = token())) switch(t) {
+
+ case DEFAULT:
+ usedefault = 1;
+ /* FALL THROUGH */
+
+ case MACH:
+ if (!usedefault) {
+ if (token() != ID)
+ continue;
+ /*
+ * Allow match either for user's input host name
+ * or official hostname. Also allow match of
+ * incompletely-specified host in local domain.
+ */
+ if (strcasecmp(host, tokval) == 0)
+ goto match;
+ if (strcasecmp(hostname, tokval) == 0)
+ goto match;
+ if ((tmp = strchr(hostname, '.')) != NULL &&
+ strcasecmp(tmp, mydomain) == 0 &&
+ strncasecmp(hostname, tokval, tmp-hostname) == 0 &&
+ tokval[tmp - hostname] == '\0')
+ goto match;
+ if ((tmp = strchr(host, '.')) != NULL &&
+ strcasecmp(tmp, mydomain) == 0 &&
+ strncasecmp(host, tokval, tmp - host) == 0 &&
+ tokval[tmp - host] == '\0')
+ goto match;
+ continue;
+ }
+ match:
+ while ((t = token()) && t != MACH && t != DEFAULT) switch(t) {
+
+ case LOGIN:
+ if (token())
+ if (*aname == 0) {
+ *aname = malloc((unsigned) strlen(tokval) + 1);
+ (void) strcpy(*aname, tokval);
+ } else {
+ if (strcmp(*aname, tokval))
+ goto next;
+ }
+ break;
+ case PASSWD:
+ if (strcmp(*aname, "anonymous") &&
+ fstat(fileno(cfile), &stb) >= 0 &&
+ (stb.st_mode & 077) != 0) {
+ fprintf(stderr, "Error - .netrc file not correct mode.\n");
+ fprintf(stderr, "Remove password or correct mode.\n");
+ goto bad;
+ }
+ if (token() && *apass == 0) {
+ *apass = malloc((unsigned) strlen(tokval) + 1);
+ (void) strcpy(*apass, tokval);
+ }
+ break;
+ case ACCOUNT:
+ if (fstat(fileno(cfile), &stb) >= 0
+ && (stb.st_mode & 077) != 0) {
+ fprintf(stderr, "Error - .netrc file not correct mode.\n");
+ fprintf(stderr, "Remove account or correct mode.\n");
+ goto bad;
+ }
+ if (token() && *aacct == 0) {
+ *aacct = malloc((unsigned) strlen(tokval) + 1);
+ (void) strcpy(*aacct, tokval);
+ }
+ break;
+ case MACDEF:
+ if (proxy) {
+ (void) fclose(cfile);
+ return(0);
+ }
+ while ((c=getc(cfile)) != EOF && c == ' ' || c == '\t');
+ if (c == EOF || c == '\n') {
+ printf("Missing macdef name argument.\n");
+ goto bad;
+ }
+ if (macnum == 16) {
+ printf("Limit of 16 macros have already been defined\n");
+ goto bad;
+ }
+ tmp = macros[macnum].mac_name;
+ *tmp++ = c;
+ for (i=0; i < 8 && (c=getc(cfile)) != EOF &&
+ !isspace(c); ++i) {
+ *tmp++ = c;
+ }
+ if (c == EOF) {
+ printf("Macro definition missing null line terminator.\n");
+ goto bad;
+ }
+ *tmp = '\0';
+ if (c != '\n') {
+ while ((c=getc(cfile)) != EOF && c != '\n');
+ }
+ if (c == EOF) {
+ printf("Macro definition missing null line terminator.\n");
+ goto bad;
+ }
+ if (macnum == 0) {
+ macros[macnum].mac_start = macbuf;
+ }
+ else {
+ macros[macnum].mac_start = macros[macnum-1].mac_end + 1;
+ }
+ tmp = macros[macnum].mac_start;
+ while (tmp != macbuf + 4096) {
+ if ((c=getc(cfile)) == EOF) {
+ printf("Macro definition missing null line terminator.\n");
+ goto bad;
+ }
+ *tmp = c;
+ if (*tmp == '\n') {
+ if (*(tmp-1) == '\0') {
+ macros[macnum++].mac_end = tmp - 1;
+ break;
+ }
+ *tmp = '\0';
+ }
+ tmp++;
+ }
+ if (tmp == macbuf + 4096) {
+ printf("4K macro buffer exceeded\n");
+ goto bad;
+ }
+ break;
+ default:
+ fprintf(stderr, "Unknown .netrc keyword %s\n", tokval);
+ break;
+ }
+ goto done;
+ }
+done:
+ (void) fclose(cfile);
+ return(0);
+bad:
+ (void) fclose(cfile);
+ return(-1);
+}
diff --git a/src/appl/gssftp/ftp/secure.c b/src/appl/gssftp/ftp/secure.c
new file mode 100644
index 0000000..4451339
--- /dev/null
+++ b/src/appl/gssftp/ftp/secure.c
@@ -0,0 +1,382 @@
+/*
+ * Shared routines for client and server for
+ * secure read(), write(), getc(), and putc().
+ * Only one security context, thus only work on one fd at a time!
+ */
+
+#include "secure.h" /* stuff which is specific to client or server */
+
+#ifdef KERBEROS
+#include <krb.h>
+
+CRED_DECL
+extern KTEXT_ST ticket;
+extern MSG_DAT msg_data;
+extern Key_schedule schedule;
+#endif /* KERBEROS */
+#ifdef GSSAPI
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_generic.h>
+extern gss_ctx_id_t gcontext;
+#endif /* GSSAPI */
+
+#include <arpa/ftp.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <errno.h>
+extern int errno;
+extern char *sys_errlist[];
+
+extern struct sockaddr_in hisaddr;
+extern struct sockaddr_in myaddr;
+extern int level;
+extern char *auth_type;
+
+#define MAX maxbuf
+extern unsigned int maxbuf; /* maximum output buffer size */
+extern unsigned char *ucbuf; /* cleartext buffer */
+static unsigned int nout, bufp; /* number of chars in ucbuf,
+ * pointer into ucbuf */
+
+#ifdef KERBEROS
+#define FUDGE_FACTOR 32 /* Amount of growth
+ * from cleartext to ciphertext.
+ * krb_mk_priv adds this # bytes.
+ * Must be defined for each auth type.
+ */
+#endif /* KERBEROS */
+
+#ifndef FUDGE_FACTOR /* In case no auth types define it. */
+#define FUDGE_FACTOR 0
+#endif
+
+#ifdef KERBEROS
+/* XXX - The following must be redefined if KERBEROS_V4 is not used
+ * but some other auth type is. They must have the same properties. */
+#define looping_write krb_net_write
+#define looping_read krb_net_read
+#endif
+
+/* perhaps use these in general, certainly use them for GSSAPI */
+
+#ifndef looping_write
+static int
+looping_write(fd, buf, len)
+ int fd;
+ register const char *buf;
+ int len;
+{
+ int cc;
+ register int wrlen = len;
+ do {
+ cc = write(fd, buf, wrlen);
+ if (cc < 0) {
+ if (errno == EINTR)
+ continue;
+ return(cc);
+ }
+ else {
+ buf += cc;
+ wrlen -= cc;
+ }
+ } while (wrlen > 0);
+ return(len);
+}
+#endif
+#ifndef looping_read
+static int
+looping_read(fd, buf, len)
+ int fd;
+ register char *buf;
+ register int len;
+{
+ int cc, len2 = 0;
+
+ do {
+ cc = read(fd, buf, len);
+ if (cc < 0) {
+ if (errno == EINTR)
+ continue;
+ return(cc); /* errno is already set */
+ }
+ else if (cc == 0) {
+ return(len2);
+ } else {
+ buf += cc;
+ len2 += cc;
+ len -= cc;
+ }
+ } while (len > 0);
+ return(len2);
+}
+#endif
+
+
+#if defined(STDARG) || (defined(__STDC__) && ! defined(VARARGS))
+extern secure_error(char *, ...);
+#else
+extern secure_error();
+#endif
+
+#define ERR -2
+
+static
+secure_putbyte(fd, c)
+int fd;
+unsigned char c;
+{
+ int ret;
+
+ ucbuf[nout++] = c;
+ if (nout == MAX - FUDGE_FACTOR)
+ if (ret = secure_putbuf(fd, ucbuf, nout))
+ return(ret);
+ else nout = 0;
+ return(c);
+}
+
+/* returns:
+ * 0 on success
+ * -1 on error (errno set)
+ * -2 on security error
+ */
+secure_flush(fd)
+int fd;
+{
+ int ret;
+
+ if (level == PROT_C)
+ return(0);
+ if (nout)
+ if (ret = secure_putbuf(fd, ucbuf, nout))
+ return(ret);
+ return(secure_putbuf(fd, "", nout = 0));
+}
+
+/* returns:
+ * c>=0 on success
+ * -1 on error
+ * -2 on security error
+ */
+secure_putc(c, stream)
+char c;
+FILE *stream;
+{
+ if (level == PROT_C)
+ return(putc(c,stream));
+ return(secure_putbyte(fileno(stream), (unsigned char) c));
+}
+
+/* returns:
+ * nbyte on success
+ * -1 on error (errno set)
+ * -2 on security error
+ */
+secure_write(fd, buf, nbyte)
+int fd;
+unsigned char *buf;
+unsigned int nbyte;
+{
+ unsigned int i;
+ int c;
+
+ if (level == PROT_C)
+ return(write(fd,buf,nbyte));
+ for (i=0; nbyte>0; nbyte--)
+ if ((c = secure_putbyte(fd, buf[i++])) < 0)
+ return(c);
+ return(i);
+}
+
+/* returns:
+ * 0 on success
+ * -1 on error (errno set)
+ * -2 on security error
+ */
+secure_putbuf(fd, buf, nbyte)
+int fd;
+unsigned char *buf;
+unsigned int nbyte;
+{
+ static char *outbuf; /* output ciphertext */
+ static unsigned int bufsize; /* size of outbuf */
+ long length;
+ u_long net_len;
+
+ if (bufsize < nbyte + FUDGE_FACTOR) {
+ if (outbuf) (void) free(outbuf);
+ if (outbuf = malloc((unsigned) (nbyte + FUDGE_FACTOR)))
+ bufsize = nbyte + FUDGE_FACTOR;
+ else {
+ bufsize = 0;
+ secure_error("%s (in malloc of PROT buffer)",
+ sys_errlist[errno]);
+ return(ERR);
+ }
+ }
+ /* Other auth types go here ... */
+#ifdef KERBEROS
+ if (strcmp(auth_type, "KERBEROS_V4") == 0)
+ if ((length = level == PROT_P ?
+ krb_mk_priv(buf, (unsigned char *) outbuf, nbyte, schedule,
+ SESSION, &myaddr, &hisaddr)
+ : krb_mk_safe(buf, (unsigned char *) outbuf, nbyte, SESSION,
+ &myaddr, &hisaddr)) == -1) {
+ secure_error("krb_mk_%s failed for KERBEROS_V4",
+ level == PROT_P ? "priv" : "safe");
+ return(ERR);
+ }
+#endif /* KERBEROS */
+#ifdef GSSAPI
+ if (strcmp(auth_type, "GSSAPI") == 0) {
+ gss_buffer_desc in_buf, out_buf;
+ OM_uint32 maj_stat, min_stat;
+ int conf_state;
+
+ in_buf.value = buf;
+ in_buf.length = nbyte;
+ maj_stat = gss_seal(&min_stat, gcontext,
+ (level == PROT_P), /* confidential */
+ GSS_C_QOP_DEFAULT,
+ &in_buf, &conf_state,
+ &out_buf);
+ if (maj_stat != GSS_S_COMPLETE) {
+ /* generally need to deal */
+ /* ie. should loop, but for now just fail */
+ secure_gss_error(maj_stat, min_stat,
+ level == PROT_P?
+ "GSSAPI seal failed":
+ "GSSAPI sign failed");
+ return(ERR);
+ }
+ memcpy(outbuf, out_buf.value, length=out_buf.length);
+ gss_release_buffer(&min_stat, &out_buf);
+
+ }
+#endif /* GSSAPI */
+ net_len = htonl((u_long) length);
+ if (looping_write(fd, &net_len, sizeof(net_len)) == -1) return(-1);
+ if (looping_write(fd, outbuf, length) != length) return(-1);
+ return(0);
+}
+
+static
+secure_getbyte(fd)
+int fd;
+{
+ /* number of chars in ucbuf, pointer into ucbuf */
+ static unsigned int nin, bufp;
+ int kerror;
+ u_long length;
+
+ if (nin == 0) {
+ if ((kerror = looping_read(fd, &length, sizeof(length)))
+ != sizeof(length)) {
+ secure_error("Couldn't read PROT buffer length: %d/%s",
+ kerror,
+ kerror == -1 ? sys_errlist[errno]
+ : "premature EOF");
+ return(ERR);
+ }
+ if ((length = (u_long) ntohl(length)) > MAX) {
+ secure_error("Length (%d) of PROT buffer > PBSZ=%u",
+ length, MAX);
+ return(ERR);
+ }
+ if ((kerror = looping_read(fd, ucbuf, length)) != length) {
+ secure_error("Couldn't read %u byte PROT buffer: %s",
+ length, kerror == -1 ?
+ sys_errlist[errno] : "premature EOF");
+ return(ERR);
+ }
+ /* Other auth types go here ... */
+#ifdef KERBEROS
+ if (strcmp(auth_type, "KERBEROS_V4") == 0) {
+ if (kerror = level == PROT_P ?
+ krb_rd_priv(ucbuf, length, schedule, SESSION,
+ &hisaddr, &myaddr, &msg_data)
+ : krb_rd_safe(ucbuf, length, SESSION,
+ &hisaddr, &myaddr, &msg_data)) {
+ secure_error("krb_rd_%s failed for KERBEROS_V4 (%s)",
+ level == PROT_P ? "priv" : "safe",
+ krb_get_err_text(kerror));
+ return(ERR);
+ }
+ memcpy(ucbuf, msg_data.app_data, msg_data.app_length);
+ nin = bufp = msg_data.app_length;
+ }
+#endif /* KERBEROS */
+#ifdef GSSAPI
+ if (strcmp(auth_type, "GSSAPI") == 0) {
+ gss_buffer_desc xmit_buf, msg_buf;
+ OM_uint32 maj_stat, min_stat;
+ int conf_state;
+
+ xmit_buf.value = ucbuf;
+ xmit_buf.length = length;
+ conf_state = (level == PROT_P);
+ /* decrypt/verify the message */
+ maj_stat = gss_unseal(&min_stat, gcontext, &xmit_buf,
+ &msg_buf, &conf_state, NULL);
+ if (maj_stat != GSS_S_COMPLETE) {
+ secure_gss_error(maj_stat, min_stat,
+ (level == PROT_P)?
+ "failed unsealing ENC message":
+ "failed unsealing MIC message");
+ return ERR;
+ }
+
+ memcpy(ucbuf, msg_buf.value, nin = bufp = msg_buf.length);
+ gss_release_buffer(&min_stat, &msg_buf);
+ }
+#endif /* GSSAPI */
+ /* Other auth types go here ... */
+ }
+ if (nin == 0)
+ return(EOF);
+ else return(ucbuf[bufp - nin--]);
+}
+
+/* returns:
+ * c>=0 on success
+ * -1 on EOF
+ * -2 on security error
+ */
+secure_getc(stream)
+FILE *stream;
+{
+ if (level == PROT_C)
+ return(getc(stream));
+ return(secure_getbyte(fileno(stream)));
+}
+
+/* returns:
+ * n>0 on success (n == # of bytes read)
+ * 0 on EOF
+ * -1 on error (errno set), only for PROT_C
+ * -2 on security error
+ */
+secure_read(fd, buf, nbyte)
+int fd;
+char *buf;
+int nbyte;
+{
+ static int c;
+ int i;
+
+ if (level == PROT_C)
+ return(read(fd,buf,nbyte));
+ if (c == EOF)
+ return(c = 0);
+ for (i=0; nbyte>0; nbyte--)
+ switch (c = secure_getbyte(fd)) {
+ case ERR: return(c);
+ case EOF: if (!i) c = 0;
+ return(i);
+ default: buf[i++] = c;
+ }
+ return(i);
+}
diff --git a/src/appl/gssftp/ftp/secure.h b/src/appl/gssftp/ftp/secure.h
new file mode 100644
index 0000000..694beda
--- /dev/null
+++ b/src/appl/gssftp/ftp/secure.h
@@ -0,0 +1,4 @@
+#define CRED_DECL extern CREDENTIALS cred;
+#define SESSION &cred.session
+#define myaddr myctladdr
+#define hisaddr hisdataaddr