diff options
author | Mark Eichin <eichin@mit.edu> | 1996-01-14 08:33:16 +0000 |
---|---|---|
committer | Mark Eichin <eichin@mit.edu> | 1996-01-14 08:33:16 +0000 |
commit | 4233c6f3143639f164290a00eb0ffe720a32b9bc (patch) | |
tree | 11e611f0bdc83991fc573882148217df9f1db53d /src/appl/gssftp/ftp | |
parent | 347ed3cc833b7d119f51f82c78aafe9e420073af (diff) | |
download | krb5-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/ChangeLog | 219 | ||||
-rw-r--r-- | src/appl/gssftp/ftp/Makefile.in | 52 | ||||
-rw-r--r-- | src/appl/gssftp/ftp/cmds.c | 2337 | ||||
-rw-r--r-- | src/appl/gssftp/ftp/cmdtab.c | 225 | ||||
-rw-r--r-- | src/appl/gssftp/ftp/configure.in | 12 | ||||
-rw-r--r-- | src/appl/gssftp/ftp/domacro.c | 153 | ||||
-rw-r--r-- | src/appl/gssftp/ftp/ftp.M | 1200 | ||||
-rw-r--r-- | src/appl/gssftp/ftp/ftp.c | 2147 | ||||
-rw-r--r-- | src/appl/gssftp/ftp/ftp_var.h | 139 | ||||
-rw-r--r-- | src/appl/gssftp/ftp/getpass.c | 73 | ||||
-rw-r--r-- | src/appl/gssftp/ftp/glob.c | 698 | ||||
-rw-r--r-- | src/appl/gssftp/ftp/main.c | 553 | ||||
-rw-r--r-- | src/appl/gssftp/ftp/pathnames.h | 37 | ||||
-rw-r--r-- | src/appl/gssftp/ftp/pclose.c | 127 | ||||
-rw-r--r-- | src/appl/gssftp/ftp/radix.c | 163 | ||||
-rw-r--r-- | src/appl/gssftp/ftp/ruserpass.c | 283 | ||||
-rw-r--r-- | src/appl/gssftp/ftp/secure.c | 382 | ||||
-rw-r--r-- | src/appl/gssftp/ftp/secure.h | 4 |
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 |