From 4233c6f3143639f164290a00eb0ffe720a32b9bc Mon Sep 17 00:00:00 2001 From: Mark Eichin Date: Sun, 14 Jan 1996 08:33:16 +0000 Subject: [PATCH] Cygnus implementation of GSSAPI-based ftp client and server. See README.gssftp for history and details. Bugs, comments to . 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 --- src/appl/gssftp/ChangeLog | 9 + src/appl/gssftp/Makefile.in | 2 + src/appl/gssftp/README.gssftp | 45 + src/appl/gssftp/arpa/ChangeLog | 5 + src/appl/gssftp/arpa/ftp.h | 128 ++ src/appl/gssftp/arpa/telnet.h | 310 ++++ src/appl/gssftp/configure.in | 5 + src/appl/gssftp/ftp/ChangeLog | 219 +++ src/appl/gssftp/ftp/Makefile.in | 52 + src/appl/gssftp/ftp/cmds.c | 2337 +++++++++++++++++++++++++++++ src/appl/gssftp/ftp/cmdtab.c | 225 +++ src/appl/gssftp/ftp/configure.in | 12 + src/appl/gssftp/ftp/domacro.c | 153 ++ src/appl/gssftp/ftp/ftp.M | 1200 +++++++++++++++ src/appl/gssftp/ftp/ftp.c | 2147 ++++++++++++++++++++++++++ src/appl/gssftp/ftp/ftp_var.h | 139 ++ src/appl/gssftp/ftp/getpass.c | 73 + src/appl/gssftp/ftp/glob.c | 698 +++++++++ src/appl/gssftp/ftp/main.c | 553 +++++++ src/appl/gssftp/ftp/pathnames.h | 37 + src/appl/gssftp/ftp/pclose.c | 127 ++ src/appl/gssftp/ftp/radix.c | 163 ++ src/appl/gssftp/ftp/ruserpass.c | 283 ++++ src/appl/gssftp/ftp/secure.c | 382 +++++ src/appl/gssftp/ftp/secure.h | 4 + src/appl/gssftp/ftpd/CHANGES | 31 + src/appl/gssftp/ftpd/ChangeLog | 232 +++ src/appl/gssftp/ftpd/Makefile.in | 69 + src/appl/gssftp/ftpd/configure.in | 31 + src/appl/gssftp/ftpd/ftpcmd.y | 1454 ++++++++++++++++++ src/appl/gssftp/ftpd/ftpd.M | 335 +++++ src/appl/gssftp/ftpd/ftpd.c | 2301 ++++++++++++++++++++++++++++ src/appl/gssftp/ftpd/logwtmp.c | 82 + src/appl/gssftp/ftpd/pathnames.h | 36 + src/appl/gssftp/ftpd/popen.c | 190 +++ src/appl/gssftp/ftpd/secure.h | 4 + src/appl/gssftp/ftpd/vers.c | 38 + 37 files changed, 14111 insertions(+) create mode 100644 src/appl/gssftp/ChangeLog create mode 100644 src/appl/gssftp/Makefile.in create mode 100644 src/appl/gssftp/README.gssftp create mode 100644 src/appl/gssftp/arpa/ChangeLog create mode 100644 src/appl/gssftp/arpa/ftp.h create mode 100644 src/appl/gssftp/arpa/telnet.h create mode 100644 src/appl/gssftp/configure.in create mode 100644 src/appl/gssftp/ftp/ChangeLog create mode 100644 src/appl/gssftp/ftp/Makefile.in create mode 100644 src/appl/gssftp/ftp/cmds.c create mode 100644 src/appl/gssftp/ftp/cmdtab.c create mode 100644 src/appl/gssftp/ftp/configure.in create mode 100644 src/appl/gssftp/ftp/domacro.c create mode 100644 src/appl/gssftp/ftp/ftp.M create mode 100644 src/appl/gssftp/ftp/ftp.c create mode 100644 src/appl/gssftp/ftp/ftp_var.h create mode 100644 src/appl/gssftp/ftp/getpass.c create mode 100644 src/appl/gssftp/ftp/glob.c create mode 100644 src/appl/gssftp/ftp/main.c create mode 100644 src/appl/gssftp/ftp/pathnames.h create mode 100644 src/appl/gssftp/ftp/pclose.c create mode 100644 src/appl/gssftp/ftp/radix.c create mode 100644 src/appl/gssftp/ftp/ruserpass.c create mode 100644 src/appl/gssftp/ftp/secure.c create mode 100644 src/appl/gssftp/ftp/secure.h create mode 100644 src/appl/gssftp/ftpd/CHANGES create mode 100644 src/appl/gssftp/ftpd/ChangeLog create mode 100644 src/appl/gssftp/ftpd/Makefile.in create mode 100644 src/appl/gssftp/ftpd/configure.in create mode 100644 src/appl/gssftp/ftpd/ftpcmd.y create mode 100644 src/appl/gssftp/ftpd/ftpd.M create mode 100644 src/appl/gssftp/ftpd/ftpd.c create mode 100644 src/appl/gssftp/ftpd/logwtmp.c create mode 100644 src/appl/gssftp/ftpd/pathnames.h create mode 100644 src/appl/gssftp/ftpd/popen.c create mode 100644 src/appl/gssftp/ftpd/secure.h create mode 100644 src/appl/gssftp/ftpd/vers.c diff --git a/src/appl/gssftp/ChangeLog b/src/appl/gssftp/ChangeLog new file mode 100644 index 000000000..ea47f8438 --- /dev/null +++ b/src/appl/gssftp/ChangeLog @@ -0,0 +1,9 @@ +Sun Jan 14 03:19:55 1996 Mark Eichin + + * README.gssftp: new file, documents history of this implementation. + +Sat Sep 30 16:28:34 1995 Mark Eichin + + * configure.in, Makefile.in: New files controlling the + construction of the GSSAPI implementation of ftp. + diff --git a/src/appl/gssftp/Makefile.in b/src/appl/gssftp/Makefile.in new file mode 100644 index 000000000..76388e8c6 --- /dev/null +++ b/src/appl/gssftp/Makefile.in @@ -0,0 +1,2 @@ +CFLAGS = $(CCOPTS) +LDFLAGS = -g diff --git a/src/appl/gssftp/README.gssftp b/src/appl/gssftp/README.gssftp new file mode 100644 index 000000000..e0dff5200 --- /dev/null +++ b/src/appl/gssftp/README.gssftp @@ -0,0 +1,45 @@ +Notes on "Secure FTP" Implementation +=============================================== +Mark Eichin , Cygnus Support +last modified: 1995 Jan 14 +=============================================== + +This implementation is supplied by Cygnus Support for inclusion in the MIT +Kerberos V5 Release. + +Copyrights: +The original BSD ftp implementation is: + * Copyright (c) 1980, 1983, 1985, 1988, 1989, 1990, 1991 Regents of the + University of California. + +History and Credits (as of 1995 Jan 14) +================================================ + +Steve Lunt at Bellcore developed the original V4 kerberized ftp. He +also started writing the IETF ftpsec draft at the time. This was +available to the public, and Cygnus eventually incorporated it into +CNS V4. + +Steve Lunt left Bellcore, and dropped out of the computer security +field altogether, after handing the draft off to Marc Horowitz at +OpenVision, who was working on a commercial GSSAPI implementation. + +Marc Horowitz left OpenVision and is back at MIT currently; in the +mean time, Cygnus took the V4 ftp and upgraded it to use GSSAPI and +draft-08, as well as integrating it into the Kerberos V5 autoconf +based configuration scheme. + +Bill Schoofs supplied corrections to the implementation +to more correctly match draft 8, as well as correcting some of the +remaining KERBEROS_V4 code. + +Karri Balk - Contractor supplied additional +corrections based on interoperation testing with non-free +implementations. + +Marc Horowitz has indicated that a draft 9 is forthcoming, with some +clarifications based on experience with this implementation. + +No other free implementation of draft-8 is known at this time. + + diff --git a/src/appl/gssftp/arpa/ChangeLog b/src/appl/gssftp/arpa/ChangeLog new file mode 100644 index 000000000..41d73c0f1 --- /dev/null +++ b/src/appl/gssftp/arpa/ChangeLog @@ -0,0 +1,5 @@ +Sun Jan 14 01:51:18 1996 Bill Schoofs + + * arpa/ftp.h: define PROT_E and add Confidential to levelnames, + so as to return more precise errors. + diff --git a/src/appl/gssftp/arpa/ftp.h b/src/appl/gssftp/arpa/ftp.h new file mode 100644 index 000000000..e20285c4c --- /dev/null +++ b/src/appl/gssftp/arpa/ftp.h @@ -0,0 +1,128 @@ +/* + * Copyright (c) 1983, 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.h 5.6 (Berkeley) 4/3/91 + */ + +#ifndef _FTP_H_ +#define _FTP_H_ + +/* Definitions for FTP; see RFC-765. */ + +/* + * Reply codes. + */ +#define PRELIM 1 /* positive preliminary */ +#define COMPLETE 2 /* positive completion */ +#define CONTINUE 3 /* positive intermediate */ +#define TRANSIENT 4 /* transient negative completion */ +#define ERROR 5 /* permanent negative completion */ + +/* + * Type codes + */ +#define TYPE_A 1 /* ASCII */ +#define TYPE_E 2 /* EBCDIC */ +#define TYPE_I 3 /* image */ +#define TYPE_L 4 /* local byte size */ + +#ifdef FTP_NAMES +char *typenames[] = {"0", "ASCII", "EBCDIC", "Image", "Local" }; +#endif + +/* + * Form codes + */ +#define FORM_N 1 /* non-print */ +#define FORM_T 2 /* telnet format effectors */ +#define FORM_C 3 /* carriage control (ASA) */ +#ifdef FTP_NAMES +char *formnames[] = {"0", "Nonprint", "Telnet", "Carriage-control" }; +#endif + +/* + * Structure codes + */ +#define STRU_F 1 /* file (no record structure) */ +#define STRU_R 2 /* record structure */ +#define STRU_P 3 /* page structure */ +#ifdef FTP_NAMES +char *strunames[] = {"0", "File", "Record", "Page" }; +#endif + +/* + * Mode types + */ +#define MODE_S 1 /* stream */ +#define MODE_B 2 /* block */ +#define MODE_C 3 /* compressed */ +#ifdef FTP_NAMES +char *modenames[] = {"0", "Stream", "Block", "Compressed" }; +#endif + +/* + * Protection levels + */ +#define PROT_C 1 /* clear */ +#define PROT_S 2 /* safe */ +#define PROT_P 3 /* private */ +#define PROT_E 4 /* confidential */ + +#ifdef FTP_NAMES +char *levelnames[] = {"0", "Clear", "Safe", "Private", "Confidential" }; +#endif + +#if defined(KERBEROS) && defined(NOENCRYPTION) +/* define away krb_rd_priv and krb_mk_priv. Don't need them anyway. */ +/* This might not be the best place for this ... */ +#define krb_rd_priv(o,l,ses,s,h,c,m) krb_rd_safe(o,l,s,h,c,m) +#define krb_mk_priv(i,o,l,ses,s,h,c) krb_mk_safe(i,o,l,s,h,c) +#endif + +/* + * Record Tokens + */ +#define REC_ESC '\377' /* Record-mode Escape */ +#define REC_EOR '\001' /* Record-mode End-of-Record */ +#define REC_EOF '\002' /* Record-mode End-of-File */ + +/* + * Block Header + */ +#define BLK_EOR 0x80 /* Block is End-of-Record */ +#define BLK_EOF 0x40 /* Block is End-of-File */ +#define BLK_ERRORS 0x20 /* Block is suspected of containing errors */ +#define BLK_RESTART 0x10 /* Block is Restart Marker */ + +#define BLK_BYTECOUNT 2 /* Bytes in this block */ + +#endif /* !_FTP_H_ */ diff --git a/src/appl/gssftp/arpa/telnet.h b/src/appl/gssftp/arpa/telnet.h new file mode 100644 index 000000000..019bfeb60 --- /dev/null +++ b/src/appl/gssftp/arpa/telnet.h @@ -0,0 +1,310 @@ +/* + * Copyright (c) 1983 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. + * + * @(#)telnet.h 5.14 (Berkeley) 4/3/91 + */ + +#ifndef _TELNET_H_ +#define _TELNET_H_ + +/* + * Definitions for the TELNET protocol. + */ +#define IAC 255 /* interpret as command: */ +#define DONT 254 /* you are not to use option */ +#define DO 253 /* please, you use option */ +#define WONT 252 /* I won't use option */ +#define WILL 251 /* I will use option */ +#define SB 250 /* interpret as subnegotiation */ +#define GA 249 /* you may reverse the line */ +#define EL 248 /* erase the current line */ +#define EC 247 /* erase the current character */ +#define AYT 246 /* are you there */ +#define AO 245 /* abort output--but let prog finish */ +#define IP 244 /* interrupt process--permanently */ +#define BREAK 243 /* break */ +#define DM 242 /* data mark--for connect. cleaning */ +#define NOP 241 /* nop */ +#define SE 240 /* end sub negotiation */ +#define EOR 239 /* end of record (transparent mode) */ +#define ABORT 238 /* Abort process */ +#define SUSP 237 /* Suspend process */ +#define xEOF 236 /* End of file: EOF is already used... */ + +#define SYNCH 242 /* for telfunc calls */ + +#ifdef TELCMDS +char *telcmds[] = { + "EOF", "SUSP", "ABORT", "EOR", + "SE", "NOP", "DMARK", "BRK", "IP", "AO", "AYT", "EC", + "EL", "GA", "SB", "WILL", "WONT", "DO", "DONT", "IAC", 0, +}; +#else +extern char *telcmds[]; +#endif + +#define TELCMD_FIRST xEOF +#define TELCMD_LAST IAC +#define TELCMD_OK(x) ((x) <= TELCMD_LAST && (x) >= TELCMD_FIRST) +#define TELCMD(x) telcmds[(x)-TELCMD_FIRST] + +/* telnet options */ +#define TELOPT_BINARY 0 /* 8-bit data path */ +#define TELOPT_ECHO 1 /* echo */ +#define TELOPT_RCP 2 /* prepare to reconnect */ +#define TELOPT_SGA 3 /* suppress go ahead */ +#define TELOPT_NAMS 4 /* approximate message size */ +#define TELOPT_STATUS 5 /* give status */ +#define TELOPT_TM 6 /* timing mark */ +#define TELOPT_RCTE 7 /* remote controlled transmission and echo */ +#define TELOPT_NAOL 8 /* negotiate about output line width */ +#define TELOPT_NAOP 9 /* negotiate about output page size */ +#define TELOPT_NAOCRD 10 /* negotiate about CR disposition */ +#define TELOPT_NAOHTS 11 /* negotiate about horizontal tabstops */ +#define TELOPT_NAOHTD 12 /* negotiate about horizontal tab disposition */ +#define TELOPT_NAOFFD 13 /* negotiate about formfeed disposition */ +#define TELOPT_NAOVTS 14 /* negotiate about vertical tab stops */ +#define TELOPT_NAOVTD 15 /* negotiate about vertical tab disposition */ +#define TELOPT_NAOLFD 16 /* negotiate about output LF disposition */ +#define TELOPT_XASCII 17 /* extended ascic character set */ +#define TELOPT_LOGOUT 18 /* force logout */ +#define TELOPT_BM 19 /* byte macro */ +#define TELOPT_DET 20 /* data entry terminal */ +#define TELOPT_SUPDUP 21 /* supdup protocol */ +#define TELOPT_SUPDUPOUTPUT 22 /* supdup output */ +#define TELOPT_SNDLOC 23 /* send location */ +#define TELOPT_TTYPE 24 /* terminal type */ +#define TELOPT_EOR 25 /* end or record */ +#define TELOPT_TUID 26 /* TACACS user identification */ +#define TELOPT_OUTMRK 27 /* output marking */ +#define TELOPT_TTYLOC 28 /* terminal location number */ +#define TELOPT_3270REGIME 29 /* 3270 regime */ +#define TELOPT_X3PAD 30 /* X.3 PAD */ +#define TELOPT_NAWS 31 /* window size */ +#define TELOPT_TSPEED 32 /* terminal speed */ +#define TELOPT_LFLOW 33 /* remote flow control */ +#define TELOPT_LINEMODE 34 /* Linemode option */ +#define TELOPT_XDISPLOC 35 /* X Display Location */ +#define TELOPT_ENVIRON 36 /* Environment variables */ +#define TELOPT_AUTHENTICATION 37/* Authenticate */ +#define TELOPT_ENCRYPT 38 /* Encryption option */ +#define TELOPT_EXOPL 255 /* extended-options-list */ + + +#define NTELOPTS (1+TELOPT_ENCRYPT) +#ifdef TELOPTS +char *telopts[NTELOPTS+1] = { + "BINARY", "ECHO", "RCP", "SUPPRESS GO AHEAD", "NAME", + "STATUS", "TIMING MARK", "RCTE", "NAOL", "NAOP", + "NAOCRD", "NAOHTS", "NAOHTD", "NAOFFD", "NAOVTS", + "NAOVTD", "NAOLFD", "EXTEND ASCII", "LOGOUT", "BYTE MACRO", + "DATA ENTRY TERMINAL", "SUPDUP", "SUPDUP OUTPUT", + "SEND LOCATION", "TERMINAL TYPE", "END OF RECORD", + "TACACS UID", "OUTPUT MARKING", "TTYLOC", + "3270 REGIME", "X.3 PAD", "NAWS", "TSPEED", "LFLOW", + "LINEMODE", "XDISPLOC", "ENVIRON", "AUTHENTICATION", + "ENCRYPT", + 0, +}; +#define TELOPT_FIRST TELOPT_BINARY +#define TELOPT_LAST TELOPT_ENCRYPT +#define TELOPT_OK(x) ((x) <= TELOPT_LAST && (x) >= TELOPT_FIRST) +#define TELOPT(x) telopts[(x)-TELOPT_FIRST] +#endif + +/* sub-option qualifiers */ +#define TELQUAL_IS 0 /* option is... */ +#define TELQUAL_SEND 1 /* send option */ +#define TELQUAL_INFO 2 /* ENVIRON: informational version of IS */ +#define TELQUAL_REPLY 2 /* AUTHENTICATION: client version of IS */ +#define TELQUAL_NAME 3 /* AUTHENTICATION: client version of IS */ + +/* + * LINEMODE suboptions + */ + +#define LM_MODE 1 +#define LM_FORWARDMASK 2 +#define LM_SLC 3 + +#define MODE_EDIT 0x01 +#define MODE_TRAPSIG 0x02 +#define MODE_ACK 0x04 +#define MODE_SOFT_TAB 0x08 +#define MODE_LIT_ECHO 0x10 + +#define MODE_MASK 0x1f + +/* Not part of protocol, but needed to simplify things... */ +#define MODE_FLOW 0x0100 +#define MODE_ECHO 0x0200 +#define MODE_INBIN 0x0400 +#define MODE_OUTBIN 0x0800 +#define MODE_FORCE 0x1000 + +#define SLC_SYNCH 1 +#define SLC_BRK 2 +#define SLC_IP 3 +#define SLC_AO 4 +#define SLC_AYT 5 +#define SLC_EOR 6 +#define SLC_ABORT 7 +#define SLC_EOF 8 +#define SLC_SUSP 9 +#define SLC_EC 10 +#define SLC_EL 11 +#define SLC_EW 12 +#define SLC_RP 13 +#define SLC_LNEXT 14 +#define SLC_XON 15 +#define SLC_XOFF 16 +#define SLC_FORW1 17 +#define SLC_FORW2 18 + +#define NSLC 18 + +/* + * For backwards compatability, we define SLC_NAMES to be the + * list of names if SLC_NAMES is not defined. + */ +#define SLC_NAMELIST "0", "SYNCH", "BRK", "IP", "AO", "AYT", "EOR", \ + "ABORT", "EOF", "SUSP", "EC", "EL", "EW", "RP", \ + "LNEXT", "XON", "XOFF", "FORW1", "FORW2", 0, +#ifdef SLC_NAMES +char *slc_names[] = { + SLC_NAMELIST +}; +#else +extern char *slc_names[]; +#define SLC_NAMES SLC_NAMELIST +#endif + +#define SLC_NAME_OK(x) ((x) >= 0 && (x) < NSLC) +#define SLC_NAME(x) slc_names[x] + +#define SLC_NOSUPPORT 0 +#define SLC_CANTCHANGE 1 +#define SLC_VARIABLE 2 +#define SLC_DEFAULT 3 +#define SLC_LEVELBITS 0x03 + +#define SLC_FUNC 0 +#define SLC_FLAGS 1 +#define SLC_VALUE 2 + +#define SLC_ACK 0x80 +#define SLC_FLUSHIN 0x40 +#define SLC_FLUSHOUT 0x20 + +#define ENV_VALUE 0 +#define ENV_VAR 1 +#define ENV_ESC 2 + +/* + * AUTHENTICATION suboptions + */ + +/* + * Who is authenticating who ... + */ +#define AUTH_WHO_CLIENT 0 /* Client authenticating server */ +#define AUTH_WHO_SERVER 1 /* Server authenticating client */ +#define AUTH_WHO_MASK 1 + +/* + * amount of authentication done + */ +#define AUTH_HOW_ONE_WAY 0 +#define AUTH_HOW_MUTUAL 2 +#define AUTH_HOW_MASK 2 + +#define AUTHTYPE_NULL 0 +#define AUTHTYPE_KERBEROS_V4 1 +#define AUTHTYPE_KERBEROS_V5 2 +#define AUTHTYPE_SPX 3 +#define AUTHTYPE_MINK 4 +#define AUTHTYPE_CNT 5 + +#define AUTHTYPE_TEST 99 + +#ifdef AUTH_NAMES +char *authtype_names[] = { + "NULL", "KERBEROS_V4", "KERBEROS_V5", "SPX", "MINK", 0, +}; +#else +extern char *authtype_names[]; +#endif + +#define AUTHTYPE_NAME_OK(x) ((x) >= 0 && (x) < AUTHTYPE_CNT) +#define AUTHTYPE_NAME(x) authtype_names[x] + +/* + * ENCRYPTion suboptions + */ +#define ENCRYPT_IS 0 /* I pick encryption type ... */ +#define ENCRYPT_SUPPORT 1 /* I support encryption types ... */ +#define ENCRYPT_REPLY 2 /* Initial setup response */ +#define ENCRYPT_START 3 /* Am starting to send encrypted */ +#define ENCRYPT_END 4 /* Am ending encrypted */ +#define ENCRYPT_REQSTART 5 /* Request you start encrypting */ +#define ENCRYPT_REQEND 6 /* Request you send encrypting */ +#define ENCRYPT_ENC_KEYID 7 +#define ENCRYPT_DEC_KEYID 8 +#define ENCRYPT_CNT 9 + +#define ENCTYPE_ANY 0 +#define ENCTYPE_DES_CFB64 1 +#define ENCTYPE_DES_OFB64 2 +#define ENCTYPE_CNT 3 + +#ifdef ENCRYPT_NAMES +char *encrypt_names[] = { + "IS", "SUPPORT", "REPLY", "START", "END", + "REQUEST-START", "REQUEST-END", "ENC-KEYID", "DEC-KEYID", + 0, +}; +char *enctype_names[] = { + "ANY", "DES_CFB64", "DES_OFB64", 0, +}; +#else +extern char *encrypt_names[]; +extern char *enctype_names[]; +#endif + + +#define ENCRYPT_NAME_OK(x) ((x) >= 0 && (x) < ENCRYPT_CNT) +#define ENCRYPT_NAME(x) encrypt_names[x] + +#define ENCTYPE_NAME_OK(x) ((x) >= 0 && (x) < ENCTYPE_CNT) +#define ENCTYPE_NAME(x) enctype_names[x] + +#endif /* !_TELNET_H_ */ diff --git a/src/appl/gssftp/configure.in b/src/appl/gssftp/configure.in new file mode 100644 index 000000000..373180bc0 --- /dev/null +++ b/src/appl/gssftp/configure.in @@ -0,0 +1,5 @@ +AC_INIT(configure.in) +CONFIG_RULES +CONFIG_DIRS(ftp ftpd) +DO_SUBDIRS +V5_AC_OUTPUT_MAKEFILE diff --git a/src/appl/gssftp/ftp/ChangeLog b/src/appl/gssftp/ftp/ChangeLog new file mode 100644 index 000000000..f1ff4ffe8 --- /dev/null +++ b/src/appl/gssftp/ftp/ChangeLog @@ -0,0 +1,219 @@ +Sun Jan 14 01:54:35 1996 Bill Schoofs + + * 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 + + * pclose.c: test HAVE_GETDTABLESIZE instead of hpux. + * configure.in: set HAVE_GETDTABLESIZE. + +Fri Oct 20 11:59:32 1995 Mark W. Eichin + + * 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 + + * configure.in: check for POSIX_TERMIOS just like appl/bsd does. + +Wed Oct 4 19:24:39 1995 Mark Eichin + + * ftp, pclose, ruserpass.c, secure.c: don't ever declare malloc. + +Sun Oct 1 03:30:30 1995 Mark Eichin + + * 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 + + * 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 + + * ftp.c, secure.c: correct gssapi includes. Fix some typos and + missing declarations. + +Sat Sep 30 21:31:09 1995 Mark Eichin + + * 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 + + * 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 + + * domacro.c: Include string.h. + * secure.c: Ditto. + +Mon Jul 10 14:54:41 1995 Michael Meissner + + * 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 + + * glob.c (matchdir): open "." explicitly if gpath is null. + +Fri May 19 16:11:07 1995 Mark Eichin + + * 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 + + * 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 + + * 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 + + * cmds.c, ftp.c: Use mygetpass instead of getpass. + + * ruserpass.c: Don't include . Don't declare getlogin, + getpass, or getuttmp. + +Thu Dec 29 15:19:44 1994 Mark Eichin + + * 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 + + * 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 + + * ftp.c: If STDARG is defined, or if __STDC__ is defined and + VARARGS is not defined, include , instead of + . + (command): Use 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 + + * 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 + + * cmds.c (gettype): Sometimes type will be zero, which requires + special handling. + + * main.c: Include . + (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 + + 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 before ftp_var.h. + * domacro.c: Move include of before include of + ftp_var.h. Don't include . + * main.c: Move include of 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 . + + 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 . 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 . + (L_SET, L_INCR): Define if not defined. + + * ftp_var.h (index, rindex): Don't declare. + * main.c: Inclue . + * pclose.c (getdtablesize): New function on hpux or __svr4__. + * radix.c (radix_encode): Cast strcmp arguments to avoid warnings. + * ruserpass.c: Include . If POSIX, include + and don't declare malloc. + (MAXHOSTNAMELEN): Define if not defined. + (index): Don't declare. + +Thu Dec 15 16:13:44 1994 Ian Lance Taylor + + * 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 000000000..06ee2daca --- /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 000000000..de7e4b117 --- /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 +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#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 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 000000000..39d171d84 --- /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 +#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 000000000..a03170bc9 --- /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 000000000..9bc277b0f --- /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 + +#include "ftp_var.h" + +#include +#include +#include +#include + +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 000000000..46291830e --- /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 000000000..6f778aba9 --- /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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#ifndef STDARG +#if defined(__STDC__) && ! defined(VARARGS) +#define STDARG +#endif +#endif +#ifdef STDARG +#include +#else +#include +#endif + +#ifdef POSIX +#include +#endif + +#ifndef L_SET +#define L_SET 0 +#endif +#ifndef L_INCR +#define L_INCR 1 +#endif + +#ifdef KERBEROS +#include + +KTEXT_ST ticket; +CREDENTIALS cred; +Key_schedule schedule; +MSG_DAT msg_data; +#endif /* KERBEROS */ +#ifdef GSSAPI +#include +#include +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 + +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 000000000..afc7d360a --- /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 +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 +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 000000000..9020373e9 --- /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 +#include + +#if defined (POSIX) || defined (POSIX_TERMIOS) +#include +static struct termios ttyo, ttyb; +#define stty(f, t) tcsetattr(f, TCSANOW, t) +#define gtty(f, t) tcgetattr(f, t) +#else +#include +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 000000000..3a793d83e --- /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 +#include +#include + +#include +#include +#include +#include +#include + +#ifdef POSIX +#include +#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 000000000..4a6d88f54 --- /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 +#include "ftp_var.h" +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#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 +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 000000000..7c0de5b0e --- /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 000000000..e1e13e451 --- /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 +#include +#include +#include +#ifdef HAVE_VFORK_H +#include +#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 +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 000000000..c651ef576 --- /dev/null +++ b/src/appl/gssftp/ftp/radix.c @@ -0,0 +1,163 @@ +#include +#include +#include + +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 000000000..5587c6c19 --- /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 +#include +#include +#ifdef POSIX +#include +#endif +#include +#include +#include +#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 000000000..445133975 --- /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 + +CRED_DECL +extern KTEXT_ST ticket; +extern MSG_DAT msg_data; +extern Key_schedule schedule; +#endif /* KERBEROS */ +#ifdef GSSAPI +#include +#include +extern gss_ctx_id_t gcontext; +#endif /* GSSAPI */ + +#include + +#include +#include +#include +#include +#include +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 000000000..694bedaf5 --- /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 diff --git a/src/appl/gssftp/ftpd/CHANGES b/src/appl/gssftp/ftpd/CHANGES new file mode 100644 index 000000000..39c7ebda0 --- /dev/null +++ b/src/appl/gssftp/ftpd/CHANGES @@ -0,0 +1,31 @@ +This version of ftpd has been fixed to conform to RFC959. + +Unfortunately, this conformance introduces a user visible change. While +technically, this is the fault of the client (ftp) instead of the server +(ftpd), the change will be seen whenever an old ftp client calls a new ftpd +server. + +The problem is that the old ftpd implemented the NLST command by execing +/bin/ls. This produced non-conformant output in some cases. The new +ftpd no longer executes /bin/ls for the NLST command as it has it's own +built-in code. + +The user visible change in the ftp behavior is caused by the ftp client +"knowing" that the daemon will exec /bin/ls. This assumption should not +have been made. + +When the old ftp client is used, one of the options is the "ls" command +which sends the command NLST to the ftpd server. The client should really +be sending the LIST command. The new ftp client has been corrected to do +this. + +NLST should not normally be used directly by humans. It is intended to +interface with commands like mget or mput. + +Users who are not able to upgrade their ftp client may obtain the previous +behavior, by using the command "dir" instead of "ls". + +These changes only apply to those sites using code derived from the Berkeley +software releases (which means almost every UNIX based implementation will +see this problem). + diff --git a/src/appl/gssftp/ftpd/ChangeLog b/src/appl/gssftp/ftpd/ChangeLog new file mode 100644 index 000000000..16813efc0 --- /dev/null +++ b/src/appl/gssftp/ftpd/ChangeLog @@ -0,0 +1,232 @@ +Sun Jan 14 02:58:42 1996 Mark Eichin + + * ftpd.c (auth_data): call gss_release_cred on the server_creds we + acquired, before they leave scope. + +Sun Jan 14 02:47:19 1996 Karri Balk - Contractor + + * ftpd.c (gss_services): list of gssapi service names to try. + (auth_data): loop over gss_services. + +Sun Jan 14 01:54:35 1996 Bill Schoofs + + * Makefile.in (DEFINES): define NOCONFIDENTIAL for future use. + * ftpcmd.y (CCC): ditch broken CCC code, return proper 534 code. + (PBSZ): return proper code 501 for bad PBSZ argument + (PROT): recognize PROT E. + (cmdtab): add CCC so as to cleanly reject it. + (getline): reject CONF as unsupported (but put in code to + potentially recognize it in the future.) Reject protected commands + of auth_type isn't yet set. + * ftpd.c (setlevel): use 536, not 504, for invalid level, and + use levelnames to find the proper name. + (user): if kuserok succeeds, respond 232, not 231; if it fails, + respond 336 (though 331 might be more appropriate.) + (auth): fix spelling error. + +Tue Jan 2 19:19:16 1996 Mark Eichin + + * ftpd.c: use HAVE_SETEUID and HAVE_SETRESUID to figure out how + to emulate seteuid instead of assuming hpux. + * configure.in: test for seteuid, setreuid and setresuid. + +Fri Oct 20 17:17:19 1995 Mark Eichin + + * ftpd.c (auth_data): supply correct channel bindings to accept, + matching the client changes. + +Thu Oct 19 12:22:28 1995 Mark W. Eichin + + * configure.in: check WITH_DBM_LNAME since we use an_to_ln. + +Wed Oct 4 19:26:50 1995 Mark Eichin + + * ftpd.c (user): use HAVE_GETUSERSHELL. + * configure.in: check for getusershell. + +Mon Oct 2 16:43:54 1995 Mark Eichin + + * popen.c (ftpd_popen): malloc all strings, not just globbed ones. + +Sun Oct 1 03:31:24 1995 Mark Eichin + + * ftpd.c (auth_data): acquire credentials (currently fixed for + service "host".) Fix loop reply logic. Add debugging syslogs. Set + auth_type *after* 235 success reply, so it doesn't get encrypted. + +Sun Oct 1 00:58:39 1995 Mark Eichin + + * Makefile.in: use FTP_BUFSIZ everywhere and make it large for + now. + * configure.in: check for headers need to build getdtablesize. + * ftpd.c (secure_reply): add GSSAPI hooks. + (reply_gss_error): better gssapi error reporting. + + +Sat Sep 30 22:26:25 1995 Mark Eichin + + * ftpd.c: correct gssapi includes. Fix type of client_name. Use + gss_ok instead of kerb_ok for GSSAPI case (to simplify future + combined code.) Fix some declarations. Fix arguments to + gss_accept_sec_context for type. + * ftpcmd.y: correct gssapi includes. + +Sat Sep 30 21:40:30 1995 Mark Eichin + + * Makefile.in: hook setenv.c and getdtablesize.c from appl/bsd. + Use double-colon rules for clean, depend, install. + configure.in: check for yacc, SIGTYPE, UTMP, SIGPROCMASK, + WAIT_TYPE, getdtablesize, getcwd, setenv (using the test from + appl/bsd.) + * ftpcmd.y: no conf.h. declare level. Use krb5_sigtype directly. + * ftpd.c: use getcwd directly, make -s srvtab KERBEROS specific. + (user): return 331 as per draft-8, but suggest 53z. + (auth_data): return 535 and 335 and quote draft-8 as to why. + (secure_gss_error): generic interface for secure.c functions to + call reply_gss_error instead. + * logwtmp.c: no conf.h, check NO_UT_HOST. + * popen.c: no conf.h, no getdtablesize. + (ftpd_pclose): Obey USE_SIGPROCMASK. + +Sat Sep 30 16:43:28 1995 Mark Eichin + + * configure.in, Makefile.in: new files for port to GSSAPI and + build within the Kerberos V5 build tree. + * ftpcmd.y, ftpd.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 daemon, which this is based on. **** + +Wed Jul 26 21:03:13 1995 Ken Raeburn + + * secure.c: Include string.h. + + * ftpd.c (main): Cast signal() return value to long instead of + int; it's more likely to fit. + +Thu Feb 2 13:41:24 1995 Ian Lance Taylor + + * ftpcmd.y (NBBY): Explicitly define if __pyrsoft and MIPSEB. + (cmd_list): In handling of SYST, undefine BSD if __svr4__ is + defined. + + * ftpd.c: Don't try to use IP_TOS if the IP_TOS argument + (IPTOS_LOWDELAY, etc.) is not defined. + +Wed Jan 18 17:12:22 1995 Ian Lance Taylor + + * ftpd.8: Include man1/tmac.doc. + +Wed Jan 11 15:29:10 1995 Ian Lance Taylor + + * ftpd.c (authenticate): New variable. + (main): Handle -a (require authentication) option. + (user): If authenticate is set, reply with an error if kuserok + fails or if no Kerberos authentication was used. + * ftpcmd.y: Use check_login when parsing the PASV command. + * ftpd.8: Document new -a option. + +Tue Jan 3 01:25:57 1995 Mark Eichin + + * Makefile.in (clean): explicitly delete ftpcmd.c on clean. + +Thu Dec 29 15:17:12 1994 Mark Eichin + + * ftpcmd.y (rcmd): don't declare atol, since it isn't used here + anyhow, and it's a macro under linux. + (top level): #define NBBY 8 for linux. + +Thu Dec 29 14:51:41 1994 Mark Eichin + + * ftpd.c (statcmd): don't use NBBY check -- linux doesn't have it, + it is in no spec, and if it isn't 8, it won't work anyway. (Use + strcat instead of sprintf, while we're at it...) + +Tue Dec 27 16:29:24 1994 Ian Lance Taylor + + * ftpcmd.y (reply, lreply): Declare if STDARG || (__STDC__ && ! + VARARGS). + * ftpd.c: If STDARG is defined, or if __STDC__ is defined and + VARARGS is not defined, include . + (secure_error): Use routines if STDARG || (__STDC__ && + ! VARARGS). + (reply, lreply): Likewise. + (setproctitle): Just use one argument. + * secure.c (secure_error): Declare if STDARG || (__STDC__ && ! + VARARGS). + +Fri Dec 23 16:25:44 1994 Ian Lance Taylor + + * ftpcmd.y (unix): Define if _AIX is defined (AIX compiler does + not predefine unix). + +Thu Dec 22 15:05:14 1994 Ian Lance Taylor + + * ftpd.c (keyfile): New global variable. + (main): Move option processing before check of remote socket. Add + new options -p, -r, and -s. Handle -p by accepting a remote + connection. + (kpass): Use keyfile variable rather than KEYFILE. Pass keyfile + explicitly to krb_rd_req. + (auth_data): Likewise. + * ftpd.8: Document new -p, -r, and -s options. + +Fri Dec 16 11:06:16 1994 Ian Lance Taylor + + Fixes for HP/UX: + * ftpd.c: On HP/UX, define seteuid and setegid as macros which + call setresuid and setresgid. + + Fixes for UnixWare: + * ftpd.c (main): Use a temporary variable rather than calling + htons(ntohs(X)). + * ftpcmd.y: Include conf.h. + (getline): Cast arguments to Kerberos routines to avoid warnings. + (toolong): Declare as type sigtype, and add dummy argument. + + Fixes for SCO: + * cmdtab.y: Include . + * ftpd.c (initgroups): Define on SCO. + (main): Don't handle SIGURG if it is not defined. + (pass): Don't try to use crypt on SCO; instead, require Kerberos + password or anonymous login. + + Fixes for AIX: + * ftpcmd.y (index): Don't define. + (strpbrk, strcpy): Don't declare. + * ftpd.c (index, rindex): Don't define. + * logwtmp.c (strncpy): Don't declare. + * secure.c: Include . + + Fixes for Ultrix: + * ftpd.c (main): Define LOG_NDELAY and LOG_DAEMON as zero if they + are not already defined by . + + Fixes for Irix 4: + * ftpd.c (retrieve): Don't refer to st_blksize if NOSTBLKSIZE is + defined. + + * ftpcmd.y: Fix yacc code to use %union and %type. + (yylex): Assign to fields of yylval, rather than to yylval + directly. + + 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: + * ftpd.c: Don't include . If POSIX is defined, include + unistd.h, otherwise define getcwd to call getwd. + (L_SET, L_INCR): Define if not defined. + (pwd): Use getcwd instead of getwd. If POSIX, change the error + handling accordingly. + * popen.c (getdtablesize): New function on hpux or __svr4__. + (ftpd_pclose): If WAIT_USES_INT, use int instead of union wait. + +Thu Dec 15 16:13:44 1994 Ian Lance Taylor + + * Initial checkin. Based on Steve Lunt's ftp program, which was + based on BSD code. diff --git a/src/appl/gssftp/ftpd/Makefile.in b/src/appl/gssftp/ftpd/Makefile.in new file mode 100644 index 000000000..edf174a00 --- /dev/null +++ b/src/appl/gssftp/ftpd/Makefile.in @@ -0,0 +1,69 @@ +# +# appl/gssftp/ftpd/Makefile.in +# +CFLAGS = -DGSSAPI -DFTP_BUFSIZ=10240 $(CCOPTS) $(DEFS) $(LOCALINCLUDE) + +SETENVSRC=@SETENVSRC@ +SETENVOBJ=@SETENVOBJ@ +COMERRLIB=$(BUILDTOP)/util/et/libcom_err.a + +SRCS = ftpd.c ftpcmd.y logwtmp.c popen.c vers.c \ + $(srcdir)../ftp/glob.c \ + $(srcdir)../ftp/radix.c \ + $(srcdir)../ftp/secure.c \ + $(srcdir)../../bsd/getdtablesize.c $(SETENVSRC) + +OBJS = ftpd.o ftpcmd.o glob.o popen.o logwtmp.o vers.o radix.o \ + secure.o getdtablesize.o $(SETENVOBJ) + +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:: ftpd + +ftpd: $(OBJS) $(DEPKLIB) + $(LD) $(LDFLAGS) $(LDARGS) -o $@ $(OBJS) $(KLIB) $(LIBS) + +clean:: + $(RM) ftp ftpcmd.c + +depend:: + +install:: + $(INSTALL_PROGRAM) ftpd $(DESTDIR)$(SERVER_BINDIR)/ftpd + $(INSTALL_DATA) $(srcdir)/ftpd.M ${DESTDIR}$(SERVER_MANDIR)/ftp.8 + + +ftpcmd.c: $(srcdir)/ftpcmd.y + $(RM) ftpcmd.c y.tab.c + $(YACC) $(srcdir)/ftpcmd.y + $(MV) y.tab.c ftpcmd.c + +glob.o: $(srcdir)/../ftp/glob.c + $(CC) -c $(CFLAGS) $(srcdir)/../ftp/glob.c +radix.o: $(srcdir)/../ftp/radix.c + $(CC) -c $(CFLAGS) $(srcdir)/../ftp/radix.c +secure.o: $(srcdir)/../ftp/secure.c + $(CC) -c $(CFLAGS) $(srcdir)/../ftp/secure.c + +getdtablesize.o: $(srcdir)/../../bsd/getdtablesize.c + $(CC) -c $(CFLAGS) $(srcdir)/../../bsd/getdtablesize.c + +setenv.o: $(srcdir)/../../bsd/setenv.c + $(CC) -c $(CFLAGS) $(srcdir)/../../bsd/setenv.c + + +ftpd.o: $(srcdir)/pathnames.h +secure.o: $(srcdir)/secure.h + +ftpd.o: $(srcdir)/ftpd.c +ftpcmd.o: ftpcmd.c +popen.o: $(srcdir)/popen.c +logwtmp.o: $(srcdir)/logwtmp.c +vers.o: $(srcdir)/vers.c + +# NOPOSTFIX diff --git a/src/appl/gssftp/ftpd/configure.in b/src/appl/gssftp/ftpd/configure.in new file mode 100644 index 000000000..9b4fd1f6b --- /dev/null +++ b/src/appl/gssftp/ftpd/configure.in @@ -0,0 +1,31 @@ +AC_INIT(ftpcmd.y) +CONFIG_RULES +AC_CONST +AC_PROG_INSTALL +AC_PROG_YACC +KRB5_SIGTYPE +CHECK_UTMP +CHECK_SIGPROCMASK +CHECK_WAIT_TYPE +AC_FUNC_VFORK +AC_CHECK_HEADERS(unistd.h stdlib.h string.h) +AC_REPLACE_FUNCS(getdtablesize) +AC_HAVE_FUNCS(getcwd getusershell seteuid setreuid setresuid) +dnl +dnl copied from appl/bsd/configure.in +AC_MSG_CHECKING([setenv]) +AC_CACHE_VAL(krb5_cv_setenv, +[AC_TRY_LINK( +[],[setenv("PATH","/bin",0);], +krb5_cv_setenv=yes,krb5_cv_setenv=no)]) +AC_MSG_RESULT($krb5_cv_setenv) +if test $krb5_cv_setenv = no; then +SETENVSRC='$(srcdir)/../bsd/setenv.c' +SETENVOBJ=setenv.o +AC_SUBST([SETENVSRC]) +AC_SUBST([SETENVOBJ]) +fi +dnl +WITH_DBM_LNAME +V5_USE_SHARED_LIB +V5_AC_OUTPUT_MAKEFILE diff --git a/src/appl/gssftp/ftpd/ftpcmd.y b/src/appl/gssftp/ftpd/ftpcmd.y new file mode 100644 index 000000000..d89b9d746 --- /dev/null +++ b/src/appl/gssftp/ftpd/ftpcmd.y @@ -0,0 +1,1454 @@ +/* -*- fundamental -*- + * Copyright (c) 1985, 1988 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. + * + * @(#)ftpcmd.y 5.24 (Berkeley) 2/25/91 + */ + +/* + * Grammar for FTP commands. + * See RFC 959. + * See Also draft-ietf-cat-ftpsec-08.txt. + */ + +%{ + +#ifndef lint +static char sccsid[] = "@(#)ftpcmd.y 5.24 (Berkeley) 2/25/91"; +#endif /* not lint */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern char *auth_type; + +unsigned int maxbuf, actualbuf; +unsigned char *ucbuf; + +#if defined(STDARG) || (defined(__STDC__) && ! defined(VARARGS)) +extern reply(int, char *, ...); +extern lreply(int, char *, ...); +#endif + +static int kerror; /* XXX needed for all auth types */ +#ifdef KERBEROS +extern struct sockaddr_in his_addr, ctrl_addr; +#include +extern AUTH_DAT kdata; +extern Key_schedule schedule; +extern MSG_DAT msg_data; +#endif /* KERBEROS */ +#ifdef GSSAPI +#include +#include +extern gss_ctx_id_t gcontext; +#endif + +#ifndef unix +#ifdef _AIX +#define unix +#endif +#endif + +#ifndef NBBY +#ifdef linux +#define NBBY 8 +#endif +#ifdef __pyrsoft +#ifdef MIPSEB +#define NBBY 8 +#endif +#endif +#endif + +extern struct sockaddr_in data_dest; +extern int logged_in; +extern struct passwd *pw; +extern int guest; +extern int logging; +extern int type; +extern int form; +extern int debug; +extern int timeout; +extern int maxtimeout; +extern int pdata; +extern char hostname[], remotehost[]; +extern char proctitle[]; +extern char *globerr; +extern int usedefault; +extern int transflag; +extern char tmpline[]; +char **ftpglob(); + +off_t restart_point; + +static int cmd_type; +static int cmd_form; +static int cmd_bytesz; +char cbuf[FTP_BUFSIZ]; /* was 512 */ +char *fromname; + +/* bison needs these decls up front */ +extern jmp_buf errcatch; + +#define CMD 0 /* beginning of command */ +#define ARGS 1 /* expect miscellaneous arguments */ +#define STR1 2 /* expect SP followed by STRING */ +#define STR2 3 /* expect STRING */ +#define OSTR 4 /* optional SP then STRING */ +#define ZSTR1 5 /* SP then optional STRING */ +#define ZSTR2 6 /* optional STRING after SP */ +#define SITECMD 7 /* SITE command */ +#define NSTR 8 /* Number followed by a string */ + +struct tab { + char *name; + short token; + short state; + short implemented; /* 1 if command is implemented */ + char *help; +}; +struct tab cmdtab[]; +struct tab sitetab[]; +%} + +%union { int num; char *str; } + +%token + A B C E F I + L N P R S T + + SP CRLF COMMA STRING NUMBER + + USER PASS ACCT REIN QUIT PORT + PASV TYPE STRU MODE RETR STOR + APPE MLFL MAIL MSND MSOM MSAM + MRSQ MRCP ALLO REST RNFR RNTO + ABOR DELE CWD LIST NLST SITE + STAT HELP NOOP MKD RMD PWD + CDUP STOU SMNT SYST SIZE MDTM + AUTH ADAT PROT PBSZ + CCC + + UMASK IDLE CHMOD + + LEXERR + +%type NUMBER +%type form_code prot_code struct_code mode_code octal_number +%type check_login byte_size + +%type STRING +%type password pathname username pathstring + +%start cmd_list + +%% + +cmd_list: /* empty */ + | cmd_list cmd + = { + fromname = (char *) 0; + restart_point = (off_t) 0; + } + | cmd_list rcmd + ; + +cmd: USER SP username CRLF + = { + user((char *) $3); + free((char *) $3); + } + | PASS SP password CRLF + = { + pass((char *) $3); + free((char *) $3); + } + | PORT SP host_port CRLF + = { + usedefault = 0; + if (pdata >= 0) { + (void) close(pdata); + pdata = -1; + } + reply(200, "PORT command successful."); + } + | PASV check_login CRLF + = { + if ($2) + passive(); + } + | PROT SP prot_code CRLF + = { + if (maxbuf) + setlevel ($3); + else + reply(503, "Must first set PBSZ"); + } + | CCC CRLF + = { + reply(534, "CCC not supported"); + } + | PBSZ SP STRING CRLF + = { + /* Others may want to do something more fancy here */ + if (!auth_type) + reply(503, "Must first perform authentication"); + else if (strlen($3) > 10 || + strlen($3) == 10 && strcmp($3,"4294967296") >= 0) + reply(501, "Bad value for PBSZ: %s", $3); + else if (actualbuf >= (maxbuf =(unsigned int) atol($3))) + reply(200, "PBSZ=%u", actualbuf); + else { + if (ucbuf) (void) free(ucbuf); + actualbuf = (unsigned int) atol($3); + /* I attempt what is asked for first, and if that + fails, I try dividing by 4 */ + while ((ucbuf = (unsigned char *)malloc(actualbuf)) == NULL) + if (actualbuf) + lreply(200, "Trying %u", actualbuf >>= 2); + else { + perror_reply(421, + "Local resource failure: malloc"); + dologout(1); + } + reply(200, "PBSZ=%u", maxbuf = actualbuf); + } + } + | TYPE SP type_code CRLF + = { + switch (cmd_type) { + + case TYPE_A: + if (cmd_form == FORM_N) { + reply(200, "Type set to A."); + type = cmd_type; + form = cmd_form; + } else + reply(504, "Form must be N."); + break; + + case TYPE_E: + reply(504, "Type E not implemented."); + break; + + case TYPE_I: + reply(200, "Type set to I."); + type = cmd_type; + break; + + case TYPE_L: +#if NBBY == 8 + if (cmd_bytesz == 8) { + reply(200, + "Type set to L (byte size 8)."); + type = cmd_type; + } else + reply(504, "Byte size must be 8."); +#else /* NBBY == 8 */ + UNIMPLEMENTED for NBBY != 8 +#endif /* NBBY == 8 */ + } + } + | STRU SP struct_code CRLF + = { + switch ($3) { + + case STRU_F: + reply(200, "STRU F ok."); + break; + + default: + reply(504, "Unimplemented STRU type."); + } + } + | MODE SP mode_code CRLF + = { + switch ($3) { + + case MODE_S: + reply(200, "MODE S ok."); + break; + + default: + reply(502, "Unimplemented MODE type."); + } + } + | ALLO SP NUMBER CRLF + = { + reply(202, "ALLO command ignored."); + } + | ALLO SP NUMBER SP R SP NUMBER CRLF + = { + reply(202, "ALLO command ignored."); + } + | RETR check_login SP pathname CRLF + = { + if ($2 && $4 != NULL) + retrieve((char *) 0, (char *) $4); + if ($4 != NULL) + free((char *) $4); + } + | STOR check_login SP pathname CRLF + = { + if ($2 && $4 != NULL) + store((char *) $4, "w", 0); + if ($4 != NULL) + free((char *) $4); + } + | APPE check_login SP pathname CRLF + = { + if ($2 && $4 != NULL) + store((char *) $4, "a", 0); + if ($4 != NULL) + free((char *) $4); + } + | NLST check_login CRLF + = { + if ($2) + send_file_list("."); + } + | NLST check_login SP STRING CRLF + = { + if ($2 && $4 != NULL) + send_file_list((char *) $4); + if ($4 != NULL) + free((char *) $4); + } + | LIST check_login CRLF + = { + if ($2) + retrieve("/bin/ls -lgA", ""); + } + | LIST check_login SP pathname CRLF + = { + if ($2 && $4 != NULL) + retrieve("/bin/ls -lgA %s", (char *) $4); + if ($4 != NULL) + free((char *) $4); + } + | STAT check_login SP pathname CRLF + = { + if ($2 && $4 != NULL) + statfilecmd((char *) $4); + if ($4 != NULL) + free((char *) $4); + } + | STAT CRLF + = { + statcmd(); + } + | DELE check_login SP pathname CRLF + = { + if ($2 && $4 != NULL) + delete((char *) $4); + if ($4 != NULL) + free((char *) $4); + } + | RNTO SP pathname CRLF + = { + if (fromname) { + renamecmd(fromname, (char *) $3); + free(fromname); + fromname = (char *) 0; + } else { + reply(503, "Bad sequence of commands."); + } + free((char *) $3); + } + | ABOR CRLF + = { + reply(225, "ABOR command successful."); + } + | CWD check_login CRLF + = { + if ($2) + cwd(pw->pw_dir); + } + | CWD check_login SP pathname CRLF + = { + if ($2 && $4 != NULL) + cwd((char *) $4); + if ($4 != NULL) + free((char *) $4); + } + | HELP CRLF + = { + help(cmdtab, (char *) 0); + } + | HELP SP STRING CRLF + = { + register char *cp = (char *)$3; + + if (strncasecmp(cp, "SITE", 4) == 0) { + cp = (char *)$3 + 4; + if (*cp == ' ') + cp++; + if (*cp) + help(sitetab, cp); + else + help(sitetab, (char *) 0); + } else + help(cmdtab, (char *) $3); + } + | NOOP CRLF + = { + reply(200, "NOOP command successful."); + } + | MKD check_login SP pathname CRLF + = { + if ($2 && $4 != NULL) + makedir((char *) $4); + if ($4 != NULL) + free((char *) $4); + } + | RMD check_login SP pathname CRLF + = { + if ($2 && $4 != NULL) + removedir((char *) $4); + if ($4 != NULL) + free((char *) $4); + } + | PWD check_login CRLF + = { + if ($2) + pwd(); + } + | CDUP check_login CRLF + = { + if ($2) + cwd(".."); + } + | SITE SP HELP CRLF + = { + help(sitetab, (char *) 0); + } + | SITE SP HELP SP STRING CRLF + = { + help(sitetab, (char *) $5); + } + | SITE SP UMASK check_login CRLF + = { + int oldmask; + + if ($4) { + oldmask = umask(0); + (void) umask(oldmask); + reply(200, "Current UMASK is %03o", oldmask); + } + } + | SITE SP UMASK check_login SP octal_number CRLF + = { + int oldmask; + + if ($4) { + if (($6 == -1) || ($6 > 0777)) { + reply(501, "Bad UMASK value"); + } else { + oldmask = umask($6); + reply(200, + "UMASK set to %03o (was %03o)", + $6, oldmask); + } + } + } + | SITE SP CHMOD check_login SP octal_number SP pathname CRLF + = { + if ($4 && ($8 != NULL)) { + if ($6 > 0777) + reply(501, + "CHMOD: Mode value must be between 0 and 0777"); + else if (chmod((char *) $8, $6) < 0) + perror_reply(550, (char *) $8); + else + reply(200, "CHMOD command successful."); + } + if ($8 != NULL) + free((char *) $8); + } + | SITE SP IDLE CRLF + = { + reply(200, + "Current IDLE time limit is %d seconds; max %d", + timeout, maxtimeout); + } + | SITE SP IDLE SP NUMBER CRLF + = { + if ($5 < 30 || $5 > maxtimeout) { + reply(501, + "Maximum IDLE time must be between 30 and %d seconds", + maxtimeout); + } else { + timeout = $5; + (void) alarm((unsigned) timeout); + reply(200, + "Maximum IDLE time set to %d seconds", + timeout); + } + } + | STOU check_login SP pathname CRLF + = { + if ($2 && $4 != NULL) + store((char *) $4, "w", 1); + if ($4 != NULL) + free((char *) $4); + } + | SYST CRLF + = { +#ifdef unix +#ifdef __svr4__ +#undef BSD +#endif +#ifdef BSD + reply(215, "UNIX Type: L%d Version: BSD-%d", + NBBY, BSD); +#else /* BSD */ + reply(215, "UNIX Type: L%d", NBBY); +#endif /* BSD */ +#else /* unix */ + reply(215, "UNKNOWN Type: L%d", NBBY); +#endif /* unix */ + } + + /* + * SIZE is not in RFC959, but Postel has blessed it and + * it will be in the updated RFC. + * + * Return size of file in a format suitable for + * using with RESTART (we just count bytes). + */ + | SIZE check_login SP pathname CRLF + = { + if ($2 && $4 != NULL) + sizecmd((char *) $4); + if ($4 != NULL) + free((char *) $4); + } + + /* + * MDTM is not in RFC959, but Postel has blessed it and + * it will be in the updated RFC. + * + * Return modification time of file as an ISO 3307 + * style time. E.g. YYYYMMDDHHMMSS or YYYYMMDDHHMMSS.xxx + * where xxx is the fractional second (of any precision, + * not necessarily 3 digits) + */ + | MDTM check_login SP pathname CRLF + = { + if ($2 && $4 != NULL) { + struct stat stbuf; + if (stat((char *) $4, &stbuf) < 0) + perror_reply(550, "%s", (char *) $4); + else if ((stbuf.st_mode&S_IFMT) != S_IFREG) { + reply(550, "%s: not a plain file.", + (char *) $4); + } else { + register struct tm *t; + struct tm *gmtime(); + t = gmtime(&stbuf.st_mtime); + reply(213, + "19%02d%02d%02d%02d%02d%02d", + t->tm_year, t->tm_mon+1, t->tm_mday, + t->tm_hour, t->tm_min, t->tm_sec); + } + } + if ($4 != NULL) + free((char *) $4); + } + | AUTH SP STRING CRLF + = { + auth((char *) $3); + } + | ADAT SP STRING CRLF + = { + auth_data((char *) $3); + free((char *) $3); + } + | QUIT CRLF + = { + reply(221, "Goodbye."); + dologout(0); + } + | error CRLF + = { + yyerrok; + } + ; +rcmd: RNFR check_login SP pathname CRLF + = { + char *renamefrom(); + + restart_point = (off_t) 0; + if ($2 && $4) { + fromname = renamefrom((char *) $4); + if (fromname == (char *) 0 && $4) { + free((char *) $4); + } + } + } + | REST SP byte_size CRLF + = { + fromname = (char *) 0; + restart_point = $3; + reply(350, "Restarting at %ld. %s", restart_point, + "Send STORE or RETRIEVE to initiate transfer."); + } + ; + +username: STRING + ; + +password: /* empty */ + = { + *(char **)&($$) = (char *)calloc(1, sizeof(char)); + } + | STRING + ; + +byte_size: NUMBER + ; + +host_port: NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA + NUMBER COMMA NUMBER + = { + register char *a, *p; + + a = (char *)&data_dest.sin_addr; + a[0] = $1; a[1] = $3; a[2] = $5; a[3] = $7; + p = (char *)&data_dest.sin_port; + p[0] = $9; p[1] = $11; + data_dest.sin_family = AF_INET; + } + ; + +form_code: N + = { + $$ = FORM_N; + } + | T + = { + $$ = FORM_T; + } + | C + = { + $$ = FORM_C; + } + ; + +prot_code: C + = { + $$ = PROT_C; + } + | S + = { + $$ = PROT_S; + } + | P + = { + $$ = PROT_P; + } + | E + = { + $$ = PROT_E; + } + ; + +type_code: A + = { + cmd_type = TYPE_A; + cmd_form = FORM_N; + } + | A SP form_code + = { + cmd_type = TYPE_A; + cmd_form = $3; + } + | E + = { + cmd_type = TYPE_E; + cmd_form = FORM_N; + } + | E SP form_code + = { + cmd_type = TYPE_E; + cmd_form = $3; + } + | I + = { + cmd_type = TYPE_I; + } + | L + = { + cmd_type = TYPE_L; + cmd_bytesz = NBBY; + } + | L SP byte_size + = { + cmd_type = TYPE_L; + cmd_bytesz = $3; + } + /* this is for a bug in the BBN ftp */ + | L byte_size + = { + cmd_type = TYPE_L; + cmd_bytesz = $2; + } + ; + +struct_code: F + = { + $$ = STRU_F; + } + | R + = { + $$ = STRU_R; + } + | P + = { + $$ = STRU_P; + } + ; + +mode_code: S + = { + $$ = MODE_S; + } + | B + = { + $$ = MODE_B; + } + | C + = { + $$ = MODE_C; + } + ; + +pathname: pathstring + = { + /* + * Problem: this production is used for all pathname + * processing, but only gives a 550 error reply. + * This is a valid reply in some cases but not in others. + */ + if (logged_in && $1 && strncmp((char *) $1, "~", 1) == 0) { + *(char **)&($$) = *ftpglob((char *) $1); + if (globerr != NULL) { + reply(550, globerr); + $$ = NULL; + } + free((char *) $1); + } else + $$ = $1; + } + ; + +pathstring: STRING + ; + +octal_number: NUMBER + = { + register int ret, dec, multby, digit; + + /* + * Convert a number that was read as decimal number + * to what it would be if it had been read as octal. + */ + dec = $1; + multby = 1; + ret = 0; + while (dec) { + digit = dec%10; + if (digit > 7) { + ret = -1; + break; + } + ret += digit * multby; + multby *= 8; + dec /= 10; + } + $$ = ret; + } + ; + +check_login: /* empty */ + = { + if (logged_in) + $$ = 1; + else { + reply(530, "Please login with USER and PASS."); + $$ = 0; + } + } + ; + +%% + +struct tab cmdtab[] = { /* In order defined in RFC 765 */ + { "USER", USER, STR1, 1, " username" }, + { "PASS", PASS, ZSTR1, 1, " password" }, + { "ACCT", ACCT, STR1, 0, "(specify account)" }, + { "SMNT", SMNT, ARGS, 0, "(structure mount)" }, + { "REIN", REIN, ARGS, 0, "(reinitialize server state)" }, + { "QUIT", QUIT, ARGS, 1, "(terminate service)", }, + { "PORT", PORT, ARGS, 1, " b0, b1, b2, b3, b4" }, + { "PASV", PASV, ARGS, 1, "(set server in passive mode)" }, + { "TYPE", TYPE, ARGS, 1, " [ A | E | I | L ]" }, + { "STRU", STRU, ARGS, 1, "(specify file structure)" }, + { "MODE", MODE, ARGS, 1, "(specify transfer mode)" }, + { "RETR", RETR, STR1, 1, " file-name" }, + { "STOR", STOR, STR1, 1, " file-name" }, + { "APPE", APPE, STR1, 1, " file-name" }, + { "MLFL", MLFL, OSTR, 0, "(mail file)" }, + { "MAIL", MAIL, OSTR, 0, "(mail to user)" }, + { "MSND", MSND, OSTR, 0, "(mail send to terminal)" }, + { "MSOM", MSOM, OSTR, 0, "(mail send to terminal or mailbox)" }, + { "MSAM", MSAM, OSTR, 0, "(mail send to terminal and mailbox)" }, + { "MRSQ", MRSQ, OSTR, 0, "(mail recipient scheme question)" }, + { "MRCP", MRCP, STR1, 0, "(mail recipient)" }, + { "ALLO", ALLO, ARGS, 1, "allocate storage (vacuously)" }, + { "REST", REST, ARGS, 1, "(restart command)" }, + { "RNFR", RNFR, STR1, 1, " file-name" }, + { "RNTO", RNTO, STR1, 1, " file-name" }, + { "ABOR", ABOR, ARGS, 1, "(abort operation)" }, + { "DELE", DELE, STR1, 1, " file-name" }, + { "CWD", CWD, OSTR, 1, "[ directory-name ]" }, + { "XCWD", CWD, OSTR, 1, "[ directory-name ]" }, + { "LIST", LIST, OSTR, 1, "[ path-name ]" }, + { "NLST", NLST, OSTR, 1, "[ path-name ]" }, + { "SITE", SITE, SITECMD, 1, "site-cmd [ arguments ]" }, + { "SYST", SYST, ARGS, 1, "(get type of operating system)" }, + { "STAT", STAT, OSTR, 1, "[ path-name ]" }, + { "HELP", HELP, OSTR, 1, "[ ]" }, + { "NOOP", NOOP, ARGS, 1, "" }, + { "MKD", MKD, STR1, 1, " path-name" }, + { "XMKD", MKD, STR1, 1, " path-name" }, + { "RMD", RMD, STR1, 1, " path-name" }, + { "XRMD", RMD, STR1, 1, " path-name" }, + { "PWD", PWD, ARGS, 1, "(return current directory)" }, + { "XPWD", PWD, ARGS, 1, "(return current directory)" }, + { "CDUP", CDUP, ARGS, 1, "(change to parent directory)" }, + { "XCUP", CDUP, ARGS, 1, "(change to parent directory)" }, + { "STOU", STOU, STR1, 1, " file-name" }, + { "AUTH", AUTH, STR1, 1, " auth-type" }, + { "ADAT", ADAT, STR1, 1, " auth-data" }, + { "PROT", PROT, ARGS, 1, " protection-level" }, + { "PBSZ", PBSZ, STR1, 1, " buffer-size" }, + { "CCC", CCC, ARGS, 1, "(clear command channel)" }, + { "SIZE", SIZE, OSTR, 1, " path-name" }, + { "MDTM", MDTM, OSTR, 1, " path-name" }, + { NULL, 0, 0, 0, 0 } +}; + +struct tab sitetab[] = { + { "UMASK", UMASK, ARGS, 1, "[ umask ]" }, + { "IDLE", IDLE, ARGS, 1, "[ maximum-idle-time ]" }, + { "CHMOD", CHMOD, NSTR, 1, " mode file-name" }, + { "HELP", HELP, OSTR, 1, "[ ]" }, + { NULL, 0, 0, 0, 0 } +}; + +struct tab * +lookup(p, cmd) + register struct tab *p; + char *cmd; +{ + + for (; p->name != NULL; p++) + if (strcmp(cmd, p->name) == 0) + return (p); + return (0); +} + +#include + +/* + * getline - a hacked up version of fgets to ignore TELNET escape codes. + */ +char * +getline(s, n, iop) + char *s; + register FILE *iop; +{ + register c; + register char *cs; + + cs = s; +/* tmpline may contain saved command from urgent mode interruption */ + for (c = 0; tmpline[c] != '\0' && --n > 0; ++c) { + *cs++ = tmpline[c]; + if (tmpline[c] == '\n') { + *cs++ = '\0'; + if (debug) + syslog(LOG_DEBUG, "command: %s", s); + tmpline[0] = '\0'; + return(s); + } + if (c == 0) + tmpline[0] = '\0'; + } + while ((c = getc(iop)) != EOF) { + c &= 0377; + if (c == IAC) { + if ((c = getc(iop)) != EOF) { + c &= 0377; + switch (c) { + case WILL: + case WONT: + c = getc(iop); + printf("%c%c%c", IAC, DONT, 0377&c); + (void) fflush(stdout); + continue; + case DO: + case DONT: + c = getc(iop); + printf("%c%c%c", IAC, WONT, 0377&c); + (void) fflush(stdout); + continue; + case IAC: + break; + default: + continue; /* ignore command */ + } + } + } + *cs++ = c; + if (--n <= 0 || c == '\n') + break; + } + if (c == EOF && cs == s) + return (NULL); + *cs++ = '\0'; + if (auth_type) { + char out[sizeof(cbuf)], *cp; + int len, mic; + + if ((cs = strpbrk(s, " \r\n"))) + *cs++ = '\0'; + upper(s); +#ifdef NOCONFIDENTIAL + if (!strcmp(s, "CONF")) { + reply(537, "CONF protected commands not supported."); + *s = '\0'; + return(s); + } +#endif + if ((mic = strcmp(s, "ENC")) && strcmp(s, "MIC") +#ifndef NOCONFIDENTIAL + && strcmp(s, "CONF") +#endif + ) { + reply(533, "All commands must be protected."); + syslog(LOG_ERR, "Unprotected command received"); + *s = '\0'; + return(s); + } else if (debug) + syslog(LOG_INFO, "command %s received (mic=%d)", s, mic); +/* Some paranoid sites may want to require that commands be encrypted. */ +#ifdef PARANOID + if (mic) { + reply(533, "All commands must be ENC protected. Retry command under ENC."); + *s = '\0'; + return(s); + } +#endif /* PARANOID */ +#ifdef NOENCRYPTION + if (!mic) { + reply(533, "ENC protection not supported. Retry command under MIC."); + *s = '\0'; + return(s); + } +#endif /* NOENCRYPTION */ + if ((cp = strpbrk(cs, " \r\n"))) + *cp = '\0'; + if (kerror = radix_encode(cs, out, &len, 1)) { + reply(501, "Can't base 64 decode argument to %s command (%s)", + mic ? "MIC" : "ENC", radix_error(kerror)); + *s = '\0'; + return(s); + } + if (debug) syslog(LOG_DEBUG, "getline got %d from %s <%s>\n", + len, cs, mic?"MIC":"ENC"); +#ifdef KERBEROS + if (strcmp(auth_type, "KERBEROS_V4") == 0) { + if ((kerror = mic ? + krb_rd_safe((unsigned char *)out, len, &kdata.session, + &his_addr, &ctrl_addr, &msg_data) + : krb_rd_priv((unsigned char *)out, len, schedule, + &kdata.session, &his_addr, &ctrl_addr, &msg_data)) + != KSUCCESS) { + reply(535, "%s! (%s)", + mic ? "MIC command modified" : "ENC command garbled", + krb_get_err_text(kerror)); + syslog(LOG_ERR,"%s failed: %s", + mic ? "MIC krb_rd_safe" : "ENC krb_rd_priv", + krb_get_err_text(kerror)); + *s = '\0'; + return(s); + } + (void) memcpy(s, msg_data.app_data, msg_data.app_length); + (void) strcpy(s+msg_data.app_length, "\r\n"); + } +#endif /* KERBEROS */ +#ifdef GSSAPI +/* we know this is a MIC or ENC already, and out/len already has the bits */ + 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 = out; + xmit_buf.length = len; + /* decrypt the message */ + conf_state = !mic; + maj_stat = gss_unseal(&min_stat, gcontext, &xmit_buf, + &msg_buf, &conf_state, NULL); + if (maj_stat == GSS_S_CONTINUE_NEEDED) { + if (debug) syslog(LOG_DEBUG, "%s-unseal continued", + mic?"MIC":"ENC"); + reply(535, "%s-unseal continued, oops", + mic?"MIC":"ENC"); + *s = 0; return s; + } + if (maj_stat != GSS_S_COMPLETE) { + reply_gss_error(535, maj_stat, min_stat, + mic? "failed unsealing MIC message": + "failed unsealing ENC message"); + *s = 0; + return s; + } + + memcpy(s, msg_buf.value, msg_buf.length); + strcpy(s+msg_buf.length-(s[msg_buf.length-1]?0:1), "\r\n"); + gss_release_buffer(&min_stat, &msg_buf); + } +#endif /* GSSAPI */ + /* Other auth types go here ... */ + } +#if defined KERBEROS || defined GSSAPI /* or other auth types */ + else { /* !auth_type */ + if ( (!(strncmp(s, "ENC", 3))) || (!(strncmp(s, "MIC", 3))) +#ifndef NOCONFIDENTIAL + || (!(strncmp(s, "CONF", 4))) +#endif + ) { + reply(503, "Must perform authentication before sending protected commands"); + *s = '\0'; + return(s); + } + } +#endif /* KERBEROS */ + + if (debug) + syslog(LOG_DEBUG, "command: <%s>(%d)", s, strlen(s)); + return (s); +} + +static krb5_sigtype +toolong(sig) + int sig; +{ + time_t now; + + reply(421, + "Timeout (%d seconds): closing control connection.", timeout); + (void) time(&now); + if (logging) { + syslog(LOG_INFO, + "User %s timed out after %d seconds at %s", + (pw ? pw -> pw_name : "unknown"), timeout, ctime(&now)); + } + dologout(1); +} + +yylex() +{ + static int cpos, state; + register char *cp, *cp2; + register struct tab *p; + int n; + char c, *copy(); + + for (;;) { + switch (state) { + + case CMD: + (void) signal(SIGALRM, toolong); + (void) alarm((unsigned) timeout); + if (getline(cbuf, sizeof(cbuf)-1, stdin) == NULL) { + reply(221, "You could at least say goodbye."); + dologout(0); + } + (void) alarm(0); +#ifdef SETPROCTITLE + if (strncasecmp(cbuf, "PASS", 4) != NULL) + setproctitle("%s: %s", proctitle, cbuf); +#endif /* SETPROCTITLE */ + if ((cp = strchr(cbuf, '\r'))) { + *cp++ = '\n'; + *cp = '\0'; + } + if ((cp = strpbrk(cbuf, " \n"))) + cpos = cp - cbuf; + if (cpos == 0) + cpos = 4; + c = cbuf[cpos]; + cbuf[cpos] = '\0'; + upper(cbuf); + p = lookup(cmdtab, cbuf); + cbuf[cpos] = c; + if (p != 0) { + if (p->implemented == 0) { + nack(p->name); + longjmp(errcatch,0); + /* NOTREACHED */ + } + state = p->state; + yylval.str = p->name; + return (p->token); + } + break; + + case SITECMD: + if (cbuf[cpos] == ' ') { + cpos++; + return (SP); + } + cp = &cbuf[cpos]; + if ((cp2 = strpbrk(cp, " \n"))) + cpos = cp2 - cbuf; + c = cbuf[cpos]; + cbuf[cpos] = '\0'; + upper(cp); + p = lookup(sitetab, cp); + cbuf[cpos] = c; + if (p != 0) { + if (p->implemented == 0) { + state = CMD; + nack(p->name); + longjmp(errcatch,0); + /* NOTREACHED */ + } + state = p->state; + yylval.str = p->name; + return (p->token); + } + state = CMD; + break; + + case OSTR: + if (cbuf[cpos] == '\n') { + state = CMD; + return (CRLF); + } + /* FALLTHROUGH */ + + case STR1: + case ZSTR1: + dostr1: + if (cbuf[cpos] == ' ') { + cpos++; + state = state == OSTR ? STR2 : ++state; + return (SP); + } + break; + + case ZSTR2: + if (cbuf[cpos] == '\n') { + state = CMD; + return (CRLF); + } + /* FALLTHROUGH */ + + case STR2: + cp = &cbuf[cpos]; + n = strlen(cp); + cpos += n - 1; + /* + * Make sure the string is nonempty and \n terminated. + */ + if (n > 1 && cbuf[cpos] == '\n') { + cbuf[cpos] = '\0'; + yylval.str = copy(cp); + cbuf[cpos] = '\n'; + state = ARGS; + return (STRING); + } + break; + + case NSTR: + if (cbuf[cpos] == ' ') { + cpos++; + return (SP); + } + if (isdigit(cbuf[cpos])) { + cp = &cbuf[cpos]; + while (isdigit(cbuf[++cpos])) + ; + c = cbuf[cpos]; + cbuf[cpos] = '\0'; + yylval.num = atoi(cp); + cbuf[cpos] = c; + state = STR1; + return (NUMBER); + } + state = STR1; + goto dostr1; + + case ARGS: + if (isdigit(cbuf[cpos])) { + cp = &cbuf[cpos]; + while (isdigit(cbuf[++cpos])) + ; + c = cbuf[cpos]; + cbuf[cpos] = '\0'; + yylval.num = atoi(cp); + cbuf[cpos] = c; + return (NUMBER); + } + switch (cbuf[cpos++]) { + + case '\n': + state = CMD; + return (CRLF); + + case ' ': + return (SP); + + case ',': + return (COMMA); + + case 'A': + case 'a': + return (A); + + case 'B': + case 'b': + return (B); + + case 'C': + case 'c': + return (C); + + case 'E': + case 'e': + return (E); + + case 'F': + case 'f': + return (F); + + case 'I': + case 'i': + return (I); + + case 'L': + case 'l': + return (L); + + case 'N': + case 'n': + return (N); + + case 'P': + case 'p': + return (P); + + case 'R': + case 'r': + return (R); + + case 'S': + case 's': + return (S); + + case 'T': + case 't': + return (T); + + } + break; + + default: + fatal("Unknown state in scanner."); + } + yyerror((char *) 0); + state = CMD; + longjmp(errcatch,0); + } +} + +upper(s) + register char *s; +{ + while (*s != '\0') { + if (islower(*s)) + *s = toupper(*s); + s++; + } +} + +char * +copy(s) + char *s; +{ + char *p; + + p = malloc((unsigned) strlen(s) + 1); + if (p == NULL) + fatal("Ran out of memory."); + (void) strcpy(p, s); + return (p); +} + +help(ctab, s) + struct tab *ctab; + char *s; +{ + register struct tab *c; + register int width, NCMDS; + char str[80]; + char *type; + + if (ctab == sitetab) + type = "SITE "; + else + type = ""; + width = 0, NCMDS = 0; + for (c = ctab; c->name != NULL; c++) { + int len = strlen(c->name); + + if (len > width) + width = len; + NCMDS++; + } + width = (width + 8) &~ 7; + if (s == 0) { + register int i, j, w; + int columns, lines; + + lreply(214, "The following %scommands are recognized %s.", + type, "(* =>'s unimplemented)"); + columns = 76 / width; + if (columns == 0) + columns = 1; + lines = (NCMDS + columns - 1) / columns; + for (i = 0; i < lines; i++) { + strcpy(str, " "); + for (j = 0; j < columns; j++) { + c = ctab + j * lines + i; + sprintf(&str[strlen(str)], "%s%c", c->name, + c->implemented ? ' ' : '*'); + if (c + lines >= &ctab[NCMDS]) + break; + w = strlen(c->name) + 1; + while (w < width) { + strcat(str, " "); + w++; + } + } + reply(0, "%s", str); + } + reply(214, "Direct comments to ftp-bugs@%s.", hostname); + return; + } + upper(s); + c = lookup(ctab, s); + if (c == (struct tab *)0) { + reply(502, "Unknown command %s.", s); + return; + } + if (c->implemented) + reply(214, "Syntax: %s%s %s", type, c->name, c->help); + else + reply(214, "%s%-*s\t%s; unimplemented.", type, width, + c->name, c->help); +} + +sizecmd(filename) +char *filename; +{ + switch (type) { + case TYPE_L: + case TYPE_I: { + struct stat stbuf; + if (stat(filename, &stbuf) < 0 || + (stbuf.st_mode&S_IFMT) != S_IFREG) + reply(550, "%s: not a plain file.", filename); + else + reply(213, "%lu", stbuf.st_size); + break;} + case TYPE_A: { + FILE *fin; + register int c; + register long count; + struct stat stbuf; + fin = fopen(filename, "r"); + if (fin == NULL) { + perror_reply(550, filename); + return; + } + if (fstat(fileno(fin), &stbuf) < 0 || + (stbuf.st_mode&S_IFMT) != S_IFREG) { + reply(550, "%s: not a plain file.", filename); + (void) fclose(fin); + return; + } + + count = 0; + while((c=getc(fin)) != EOF) { + if (c == '\n') /* will get expanded to \r\n */ + count++; + count++; + } + (void) fclose(fin); + + reply(213, "%ld", count); + break;} + default: + reply(504, "SIZE not implemented for Type %c.", "?AEIL"[type]); + } +} diff --git a/src/appl/gssftp/ftpd/ftpd.M b/src/appl/gssftp/ftpd/ftpd.M new file mode 100644 index 000000000..2b4e9951d --- /dev/null +++ b/src/appl/gssftp/ftpd/ftpd.M @@ -0,0 +1,335 @@ +.\" Copyright (c) 1985, 1988, 1991 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. +.\" +.\" @(#)ftpd.8 6.9 (Berkeley) 3/16/91 +.\" +.so man1/tmac.doc +.Dd March 16, 1991 +.Dt FTPD 8 +.Os BSD 4.2 +.Sh NAME +.Nm ftpd +.Nd +.Tn DARPA +Internet File Transfer Protocol server +.Sh SYNOPSIS +.Nm ftpd +.Op Fl d +.Op Fl l +.Op Fl t Ar timeout +.Op Fl T Ar maxtimeout +.Op Fl p Ar port +.Op Fl r Ar realm-file +.Op Fl s Ar srvtab +.Sh DESCRIPTION +.Nm Ftpd +is the +.Tn DARPA +Internet File Transfer Protocol +server process. The server uses the +.Tn TCP +protocol +and listens at the port specified in the +.Dq ftp +service specification; see +.Xr services 5 . +.Pp +Available options: +.Bl -tag -width Ds +.It Fl d +Debugging information is written to the syslog. +.It Fl l +Each +.Xr ftp 1 +session is logged in the syslog. +.It Fl t +The inactivity timeout period is set to +.Ar timeout +seconds (the default is 15 minutes). +.It Fl T +A client may also request a different timeout period; +the maximum period allowed may be set to +.Ar timeout +seconds with the +.Fl T +option. +The default limit is 2 hours. +.It Fl a +Only permit Kerberos authenticated or anonymous logins. +.It Fl p Ar port +Run as a server and accept a connection on +.Ar port. +Normally the ftp server is invoked by +.Xr inetd 8 . +.It Fl r Ar realm-file +Sets the name of the +.Pa krb.conf +file to use. The default value is normally +.Pa /usr/kerberos/lib/krb.conf. +.It Fl s Ar srvtab +Sets the name of the +.Pa srvtab +file to use. The default value is normally +.Pa /etc/krb-srvtab. +.El +.Pp +The ftp server currently supports the following ftp +requests; case is not distinguished. +.Bl -column "Request" -offset indent +.It Request Ta "Description" +.It ABOR Ta "abort previous command" +.It ACCT Ta "specify account (ignored)" +.It ADAT Ta "send an authentication protocol message" +.It ALLO Ta "allocate storage (vacuously)" +.It APPE Ta "append to a file" +.It AUTH Ta "specify an authentication protocol to be performed" +.It CDUP Ta "change to parent of current working directory" +.It CWD Ta "change working directory" +.It DELE Ta "delete a file" +.It ENC Ta "send a privacy and integrity protected command (given in argument)" +.It HELP Ta "give help information" +.It LIST Ta "give list files in a directory" Pq Dq Li "ls -lgA" +.It MIC Ta "send an integrity protected command (given in argument)" +.It MKD Ta "make a directory" +.It MDTM Ta "show last modification time of file" +.It MODE Ta "specify data transfer" Em mode +.It NLST Ta "give name list of files in directory" +.It NOOP Ta "do nothing" +.It PASS Ta "specify password" +.It PASV Ta "prepare for server-to-server transfer" +.It PBSZ Ta "specify a protection buffer size" +.It PORT Ta "specify data connection port" +.It PROT Ta "specify a protection level under which to protect data transfers" +.It PWD Ta "print the current working directory" +.It QUIT Ta "terminate session" +.It REST Ta "restart incomplete transfer" +.It RETR Ta "retrieve a file" +.It RMD Ta "remove a directory" +.It RNFR Ta "specify rename-from file name" +.It RNTO Ta "specify rename-to file name" +.It SITE Ta "non-standard commands (see next section)" +.It SIZE Ta "return size of file" +.It STAT Ta "return status of server" +.It STOR Ta "store a file" +.It STOU Ta "store a file with a unique name" +.It STRU Ta "specify data transfer" Em structure +.It SYST Ta "show operating system type of server system" +.It TYPE Ta "specify data transfer" Em type +.It USER Ta "specify user name" +.It XCUP Ta "change to parent of current working directory (deprecated)" +.It XCWD Ta "change working directory (deprecated)" +.It XMKD Ta "make a directory (deprecated)" +.It XPWD Ta "print the current working directory (deprecated)" +.It XRMD Ta "remove a directory (deprecated)" +.El +.Pp +The following non-standard or +.Tn UNIX +specific commands are supported +by the +SITE request. +.Pp +.Bl -column Request -offset indent +.It Sy Request Ta Sy Description +.It UMASK Ta change umask. Em E.g. SITE UMASK 002 +.It IDLE Ta set idle-timer. Em E.g. SITE IDLE 60 +.It CHMOD Ta change mode of a file. Em E.g. +SITE CHMOD 755 filename +.It HELP Ta give help information. Em E.g. SITE HELP +.El +.Pp +The remaining ftp requests specified in Internet +.%T "RFC 959" +are +recognized, but not implemented. +MDTM and SIZE are not specified in +.%T "RFC 959" , +but will appear in the next updated FTP RFC. +.Pp +The ftp server will abort an active file transfer only when the +ABOR +command is preceded by a Telnet "Interrupt Process" (IP) +signal and a Telnet "Synch" signal in the command Telnet stream, +as described in Internet +.%T "RFC 959" . +If a +STAT +command is received during a data transfer, preceded by a Telnet IP +and Synch, transfer status will be returned. +.Pp +.Nm Ftpd +interprets file names according to the +.Dq globbing +conventions used by +.Xr csh 1 . +This allows users to utilize the metacharacters +.Dq Li \&*?[]{}~ . +.Pp +.Nm Ftpd +authenticates users according to the following rules: +.Pp +.Bl -enum -offset indent +.It +The user name must be in the password data base, +.Pa /etc/passwd . +.It +An +.Dv AUTH +command must be accepted, the ensuing authentication protocol +(conducted via +.Dv ADAT +commands and replies) +must successfully complete, and the authenticated user must permitted +access. Otherwise, a valid password which is not null +must be provided by the client. +.It +The user name must not appear in the file +.Pa /etc/ftpusers . +.It +The user must have a standard shell returned by +.Xr getusershell 3 . +.It +If the user name is +.Dq anonymous +or +.Dq ftp , +an +anonymous ftp account must be present in the password +file (user +.Dq ftp ) . +In this case the user is allowed +to log in by specifying any password (by convention this +is given as the client host's name). +.El +.Pp +In the last case, +.Nm ftpd +takes special measures to restrict the client's access privileges. +The server performs a +.Xr chroot 2 +command to the home directory of the +.Dq ftp +user. +In order that system security is not breached, it is recommended +that the +.Dq ftp +subtree be constructed with care; the following +rules are recommended. +.Bl -tag -width "~ftp/pub" -offset indent +.It Pa ~ftp +Make the home directory owned by +.Dq ftp +and unwritable by anyone. +.It Pa ~ftp/bin +Make this directory owned by the super-user and unwritable by +anyone. The program +.Xr ls 1 +must be present to support the list command. This +program should have mode 111. +.It Pa ~ftp/etc +Make this directory owned by the super-user and unwritable by +anyone. The files +.Xr passwd 5 +and +.Xr group 5 +must be present for the +.Xr ls +command to be able to produce owner names rather than numbers. +The password field in +.Xr passwd +is not used, and should not contain real encrypted passwords. +These files should be mode 444. +.It Pa ~ftp/pub +Make this directory mode 777 and owned by +.Dq ftp . +Users +should then place files which are to be accessible via the +anonymous account in this directory. +.El +.Pp +If an +.Dv ADAT +command succeeds, the control channel must be either +integrity or privacy protected. +In this case, the +.Dv MIC +and +.Dv ENC +commands are the only commands allowed over the control channel. +The argument to the +.Dv MIC +command is a base 64 encoded string which, when decoded, is an +ftp command integrity protected with a cryptographic checksum. +The argument to the +.Dv ENC +command is a base 64 encoded string which, when decoded, is an +ftp command privacy and integrity protected with encryption. +.Pp +If an +.Dv ADAT +command succeeds, +ftp replies will also be either integrity or privacy protected. +.Pp +If an +.Dv ADAT +command succeeds, the data channel can also be integrity or privacy protected. +The +.Dv PROT +command accepts S for integrity and P for privacy protection. +Unless an +.Dv ADAT +command succeeds, the only protection level accepted by the +.Dv PROT +command is C (clear). +.Sh SEE ALSO +.Xr ftp 1 , +.Xr getusershell 3 , +.Xr syslogd 8 +.Pp +Lunt, S. J., +FTP Security Extensions, +Internet Draft, +November 1993. +.Sh BUGS +The anonymous account is inherently dangerous and should +avoided when possible. +.Pp +The server must run as the super-user +to create sockets with privileged port numbers. It maintains +an effective user id of the logged in user, reverting to +the super-user only when binding addresses to sockets. The +possible security holes have been extensively +scrutinized, but are possibly incomplete. +.Sh HISTORY +The +.Nm +command appeared in +.Bx 4.2 . diff --git a/src/appl/gssftp/ftpd/ftpd.c b/src/appl/gssftp/ftpd/ftpd.c new file mode 100644 index 000000000..2a1bff3f4 --- /dev/null +++ b/src/appl/gssftp/ftpd/ftpd.c @@ -0,0 +1,2301 @@ +/* + * Copyright (c) 1985, 1988, 1990 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, 1988, 1990 Regents of the University of California.\n\ + All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)ftpd.c 5.40 (Berkeley) 7/2/91"; +#endif /* not lint */ + +/* + * FTP server. + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define FTP_NAMES +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef STDARG +#if defined(__STDC__) && ! defined(VARARGS) +#define STDARG +#endif +#endif +#ifdef STDARG +#include +#endif +#include "pathnames.h" + +#ifndef L_SET +#define L_SET 0 +#endif +#ifndef L_INCR +#define L_INCR 1 +#endif + +#define strerror(error) (sys_errlist[error]) +extern char *sys_errlist[]; + +extern char *mktemp (); + +#ifndef HAVE_SETEUID +#ifdef HAVE_SETRESUID +#define seteuid(e) setresuid(-1,e,-1) +#define setegid(e) setresgid(-1,e,-1) +#endif +#endif + +#ifdef STDARG +extern reply(int, char *, ...); +extern lreply(int, char *, ...); +#endif + +#ifdef KERBEROS +#include + +AUTH_DAT kdata; +KTEXT_ST ticket; +MSG_DAT msg_data; +Key_schedule schedule; +int kerb_ok; /* Kerberos authentication and authorization succeeded */ +char *keyfile = KEYFILE; +#endif /* KERBEROS */ + +#ifdef GSSAPI +#include +#include +gss_ctx_id_t gcontext; +gss_buffer_desc client_name; +int gss_ok; /* GSSAPI authentication and userok authorization succeeded */ +char* gss_services[] = { "ftp", "host", 0 }; +#endif /* GSSAPI */ + +char *auth_type; /* Authentication succeeded? If so, what type? */ +static char *temp_auth_type; + +/* + * File containing login names + * NOT to be used on this machine. + * Commonly used to disallow uucp. + */ +extern int errno; +extern char *crypt(); +extern char version[]; +extern char *home; /* pointer to home directory for glob */ +extern FILE *ftpd_popen(), *fopen(), *freopen(); +extern int ftpd_pclose(), fclose(); +extern char *getline(); +extern char cbuf[]; +extern off_t restart_point; + +struct sockaddr_in ctrl_addr; +struct sockaddr_in data_source; +struct sockaddr_in data_dest; +struct sockaddr_in his_addr; +struct sockaddr_in pasv_addr; + +int data; +jmp_buf errcatch, urgcatch; +int logged_in; +struct passwd *pw; +int debug; +int timeout = 900; /* timeout after 15 minutes of inactivity */ +int maxtimeout = 7200;/* don't allow idle time to be set beyond 2 hours */ +int logging; +int authenticate; +int guest; +int type; +int level; +int form; +int stru; /* avoid C keyword */ +int mode; +int usedefault = 1; /* for data transfers */ +int pdata = -1; /* for passive mode */ +int transflag; +off_t file_size; +off_t byte_count; +#if !defined(CMASK) || CMASK == 0 +#undef CMASK +#define CMASK 027 +#endif +int defumask = CMASK; /* default umask value */ +char tmpline[FTP_BUFSIZ]; +char hostname[MAXHOSTNAMELEN]; +char remotehost[MAXHOSTNAMELEN]; + +/* + * Timeout intervals for retrying connections + * to hosts that don't accept PORT cmds. This + * is a kludge, but given the problems with TCP... + */ +#define SWAITMAX 90 /* wait at most 90 seconds */ +#define SWAITINT 5 /* interval between retries */ + +int swaitmax = SWAITMAX; +int swaitint = SWAITINT; + +void lostconn(), myoob(); +FILE *getdatasock(), *dataconn(); + +#ifdef SETPROCTITLE +char **Argv = NULL; /* pointer to argument vector */ +char *LastArgv = NULL; /* end of argv */ +char proctitle[FTP_BUFSIZ]; /* initial part of title */ +#endif /* SETPROCTITLE */ + +#ifdef __SCO__ +/* sco has getgroups and setgroups but no initgroups */ +int initgroups(char* name, gid_t basegid) { + gid_t others[NGROUPS_MAX+1]; + int ngrps; + + others[0] = basegid; + ngrps = getgroups(NGROUPS_MAX, others+1); + return setgroups(ngrps+1, others); +} +#endif + +main(argc, argv, envp) + int argc; + char *argv[]; + char **envp; +{ + int addrlen, on = 1, tos, port = -1; + char *cp; + + debug = 0; +#ifdef SETPROCTITLE + /* + * Save start and extent of argv for setproctitle. + */ + Argv = argv; + while (*envp) + envp++; + LastArgv = envp[-1] + strlen(envp[-1]); +#endif /* SETPROCTITLE */ + + argc--, argv++; + while (argc > 0 && *argv[0] == '-') { + for (cp = &argv[0][1]; *cp; cp++) switch (*cp) { + + case 'v': + debug = 1; + break; + + case 'd': + debug = 1; + break; + + case 'l': + logging = 1; + break; + + case 'a': + authenticate = 1; + break; + + case 'p': + if (*++cp != '\0') + port = atoi(cp); + else if (argc > 1) { + argc--, argv++; + port = atoi(*argv); + } + else + fprintf(stderr, "ftpd: -p expects argument\n"); + goto nextopt; + + case 'r': + if (*++cp != '\0') + setenv("KRB_CONF", cp, 1); + else if (argc > 1) { + argc--, argv++; + setenv("KRB_CONF", *argv, 1); + } + else + fprintf(stderr, "ftpd: -r expects argument\n"); + goto nextopt; + +#ifdef KERBEROS + case 's': + if (*++cp != '\0') + keyfile = cp; + else if (argc > 1) { + argc--, argv++; + keyfile = *argv; + } + else + fprintf(stderr, "ftpd: -s expects argument\n"); + goto nextopt; + +#endif /* KERBEROS */ + case 't': + timeout = atoi(++cp); + if (maxtimeout < timeout) + maxtimeout = timeout; + goto nextopt; + + case 'T': + maxtimeout = atoi(++cp); + if (timeout > maxtimeout) + timeout = maxtimeout; + goto nextopt; + + case 'u': + { + int val = 0; + + while (*++cp && *cp >= '0' && *cp <= '9') + val = val*8 + *cp - '0'; + if (*cp) + fprintf(stderr, "ftpd: Bad value for -u\n"); + else + defumask = val; + goto nextopt; + } + + default: + fprintf(stderr, "ftpd: Unknown flag -%c ignored.\n", + *cp); + break; + } +nextopt: + argc--, argv++; + } + + if (port != -1) { + struct sockaddr_in sin; + int s, ns, sz; + + /* Accept an incoming connection on port. */ + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = INADDR_ANY; + sin.sin_port = htons(port); + s = socket(AF_INET, SOCK_STREAM, 0); + if (s < 0) { + perror("socket"); + exit(1); + } + (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR, + (char *)&on, sizeof(on)); + if (bind(s, (struct sockaddr *)&sin, sizeof sin) < 0) { + perror("bind"); + exit(1); + } + if (listen(s, 1) < 0) { + perror("listen"); + exit(1); + } + sz = sizeof sin; + ns = accept(s, (struct sockaddr *)&sin, &sz); + if (ns < 0) { + perror("accept"); + exit(1); + } + (void) close(s); + (void) dup2(ns, 0); + (void) dup2(ns, 1); + (void) dup2(ns, 2); + if (ns > 2) + (void) close(ns); + } + + /* + * LOG_NDELAY sets up the logging connection immediately, + * necessary for anonymous ftp's that chroot and can't do it later. + */ +#ifndef LOG_NDELAY +/* Ultrix syslog does not support NDELAY. */ +#define LOG_NDELAY 0 +#endif +#ifndef LOG_DAEMON +#define LOG_DAEMON 0 +#endif + openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_DAEMON); + addrlen = sizeof (his_addr); + if (getpeername(0, (struct sockaddr *)&his_addr, &addrlen) < 0) { + syslog(LOG_ERR, "getpeername (%s): %m",argv[0]); + exit(1); + } + addrlen = sizeof (ctrl_addr); + if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) { + syslog(LOG_ERR, "getsockname (%s): %m",argv[0]); + exit(1); + } +#ifdef IP_TOS +#ifdef IPTOS_LOWDELAY + tos = IPTOS_LOWDELAY; + if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0) + syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); +#endif +#endif + port = ntohs(ctrl_addr.sin_port); + data_source.sin_port = htons(port - 1); + + (void) freopen("/dev/null", "w", stderr); + (void) signal(SIGPIPE, lostconn); + (void) signal(SIGCHLD, SIG_IGN); +#ifdef SIGURG + if ((long)signal(SIGURG, myoob) < 0) + syslog(LOG_ERR, "signal: %m"); +#endif + + /* Try to handle urgent data inline */ +#ifdef SO_OOBINLINE + if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on)) < 0) + syslog(LOG_ERR, "setsockopt: %m"); +#endif + +#ifdef F_SETOWN + if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1) + syslog(LOG_ERR, "fcntl F_SETOWN: %m"); +#endif + dolog(&his_addr); + /* + * Set up default state + */ + data = -1; + level = PROT_C; + type = TYPE_A; + form = FORM_N; + stru = STRU_F; + mode = MODE_S; + tmpline[0] = '\0'; + (void) gethostname(hostname, sizeof (hostname)); + reply(220, "%s FTP server (%s) ready.", hostname, version); + (void) setjmp(errcatch); + for (;;) + (void) yyparse(); + /* NOTREACHED */ +} + +void +lostconn() +{ + if (debug) + syslog(LOG_DEBUG, "lost connection"); + dologout(-1); +} + +static char ttyline[20]; + +/* + * Helper function for sgetpwnam(). + */ +char * +sgetsave(s) + char *s; +{ + char *new = malloc((unsigned) strlen(s) + 1); + + if (new == NULL) { + perror_reply(421, "Local resource failure: malloc"); + dologout(1); + /* NOTREACHED */ + } + (void) strcpy(new, s); + return (new); +} + +/* + * Save the result of a getpwnam. Used for USER command, since + * the data returned must not be clobbered by any other command + * (e.g., globbing). + */ +struct passwd * +sgetpwnam(name) + char *name; +{ + static struct passwd save; + register struct passwd *p; + char *sgetsave(); + + if ((p = getpwnam(name)) == NULL) + return (p); + if (save.pw_name) { + free(save.pw_name); + free(save.pw_passwd); + free(save.pw_gecos); + free(save.pw_dir); + free(save.pw_shell); + } + save = *p; + save.pw_name = sgetsave(p->pw_name); + save.pw_passwd = sgetsave(p->pw_passwd); + save.pw_gecos = sgetsave(p->pw_gecos); + save.pw_dir = sgetsave(p->pw_dir); + save.pw_shell = sgetsave(p->pw_shell); + return (&save); +} + +setlevel(prot_level) +int prot_level; +{ + switch (prot_level) { + case PROT_S: +#ifndef NOENCRYPTION + case PROT_P: +#endif + if (auth_type) + case PROT_C: + reply(200, "Protection level set to %s.", + (level = prot_level) == PROT_S ? + "Safe" : level == PROT_P ? + "Private" : "Clear"); + else + default: reply(536, "%s protection level not supported.", + levelnames[prot_level]); + } +} + +int login_attempts; /* number of failed login attempts */ +int askpasswd; /* had user command, ask for passwd */ + +/* + * USER command. + * Sets global passwd pointer pw if named account exists and is acceptable; + * sets askpasswd if a PASS command is expected. If logged in previously, + * need to reset state. If name is "ftp" or "anonymous", the name is not in + * _PATH_FTPUSERS, and ftp account exists, set guest and pw, then just return. + * If account doesn't exist, ask for passwd anyway. Otherwise, check user + * requesting login privileges. Disallow anyone who does not have a standard + * shell as returned by getusershell(). Disallow anyone mentioned in the file + * _PATH_FTPUSERS to allow people such as root and uucp to be avoided. + */ +user(name) + char *name; +{ + register char *cp; + char *shell; +#ifdef HAVE_GETUSERSHELL + char *getusershell(); +#endif + + /* Some paranoid sites may want the client to authenticate + * before accepting the USER command. If so, uncomment this: + + if (!auth_type) { + reply(530, + "Must perform authentication before identifying USER."); + return; + */ + if (logged_in) { + if (guest) { + reply(530, "Can't change user from guest login."); + return; + } + end_login(); + } + + guest = 0; + if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) { + if (checkuser("ftp") || checkuser("anonymous")) + reply(530, "User %s access denied.", name); + else if ((pw = sgetpwnam("ftp")) != NULL) { + guest = 1; + askpasswd = 1; + reply(331, "Guest login ok, send ident as password."); + } else + reply(530, "User %s unknown.", name); + return; + } + if (pw = sgetpwnam(name)) { + if ((shell = pw->pw_shell) == NULL || *shell == 0) + shell = "/bin/sh"; +#ifdef HAVE_GETUSERSHELL + while ((cp = getusershell()) != NULL) + if (strcmp(cp, shell) == 0) + break; + /* endusershell(); */ /* this breaks on solaris 2.4 */ +#else + cp = shell; +#endif + if (cp == NULL || checkuser(name)) { + reply(530, "User %s access denied.", name); + if (logging) + syslog(LOG_NOTICE, + "FTP LOGIN REFUSED FROM %s, %s", + remotehost, name); + pw = (struct passwd *) NULL; + return; + } + } +#ifdef KERBEROS + if (auth_type && strcmp(auth_type, "KERBEROS_V4") == 0) { + char buf[FTP_BUFSIZ]; + kerb_ok = kuserok(&kdata,name) == 0; + if (! kerb_ok && authenticate) { + reply(530, "User %s access denied.", name); + if (logging) + syslog(LOG_NOTICE, + "FTP KERBEROS LOGIN REFUSED FROM %s, %s", + remotehost, name); + pw = (struct passwd *) NULL; + return; + } + sprintf(buf, "Kerberos user %s%s%s@%s is%s authorized as %s%s", + kdata.pname, *kdata.pinst ? "." : "", + kdata.pinst, kdata.prealm, + kerb_ok ? "" : " not", + name, kerb_ok ? "" : "; Password required."); + reply(kerb_ok ? 232 : 336, "%s", buf); + syslog(kerb_ok ? LOG_INFO : LOG_ERR, "%s", buf); + } else +#endif /* KERBEROS */ +#ifdef GSSAPI + if (auth_type && strcmp(auth_type, "GSSAPI") == 0) { + char buf[FTP_BUFSIZ]; + gss_ok = ftpd_userok(&client_name, name) == 0; + if (! gss_ok && authenticate) { + reply(530, "User %s access denied.", name); + if (logging) + syslog(LOG_NOTICE, + "FTP GSSAPI LOGIN REFUSED FROM %s, %s", + remotehost, name); + pw = (struct passwd *) NULL; + return; + } + sprintf(buf, "GSSAPI user %s is%s authorized as %s%s", + client_name.value, + gss_ok ? "" : " not", + name, gss_ok ? "" : "; Password required."); + /* 232 is per draft-8, but why 331 not 53z? */ + reply(gss_ok ? 232 : 331, "%s", buf); + syslog(gss_ok ? LOG_INFO : LOG_ERR, "%s", buf); + } else +#endif /* GSSAPI */ + /* Other auth types go here ... */ + if (authenticate) { + reply(530, "User %s access denied: authentication required.", + name); + if (logging) + syslog(LOG_NOTICE, + "FTP LOGIN REFUSED FROM %s, %s", + remotehost, name); + pw = (struct passwd *) NULL; + return; + } else + reply(331, "Password required for %s.", name); + askpasswd = 1; + /* + * Delay before reading passwd after first failed + * attempt to slow down passwd-guessing programs. + */ + if (login_attempts) + sleep((unsigned) login_attempts); +} + +/* + * Check if a user is in the file _PATH_FTPUSERS + */ +checkuser(name) + char *name; +{ + register FILE *fd; + register char *p; + char line[FTP_BUFSIZ]; + + if ((fd = fopen(_PATH_FTPUSERS, "r")) != NULL) { + while (fgets(line, sizeof(line), fd) != NULL) + if ((p = strchr(line, '\n')) != NULL) { + *p = '\0'; + if (line[0] == '#') + continue; + if (strcmp(line, name) == 0) + return (1); + } + (void) fclose(fd); + } + return (0); +} + +/* + * Terminate login as previous user, if any, resetting state; + * used when USER command is given or login fails. + */ +end_login() +{ + + (void) seteuid((uid_t)0); + if (logged_in) + logwtmp(ttyline, "", ""); + pw = NULL; + logged_in = 0; + guest = 0; +} + +#ifdef KERBEROS +static char *services[] = { "ftp", "rcmd", NULL }; + +kpass(name, passwd) +char *name, *passwd; +{ + char **service; + char instance[INST_SZ]; + char realm[REALM_SZ]; + char tkt_file[20]; + KTEXT_ST ticket; + AUTH_DAT authdata; + des_cblock key; + unsigned long faddr; + struct hostent *hp; + + if (krb_get_lrealm(realm, 1) != KSUCCESS) + return(0); + + strcpy(tkt_file, TKT_ROOT); + strcat(tkt_file, "_ftpdXXXXXX"); + krb_set_tkt_string(mktemp(tkt_file)); + + (void) strncpy(instance, krb_get_phost(hostname), sizeof(instance)); + + if ((hp = gethostbyname(instance)) == NULL) + return(0); + + memcpy((char *) &faddr, (char *)hp->h_addr, sizeof(faddr)); + + if (krb_get_pw_in_tkt(name, "", realm, "krbtgt", realm, 1, passwd)) { + for (service = services; *service; service++) + if (!read_service_key(*service, instance, realm, 0, keyfile, key)) { + (void) memset(key, 0, sizeof(key)); + if (krb_mk_req(&ticket, *service, instance, realm, 33) || + krb_rd_req(&ticket, *service, instance, faddr, &authdata,keyfile)|| + kuserok(&authdata, name)) { + dest_tkt(); + return(0); + } else { + dest_tkt(); + return(1); + } + } + dest_tkt(); + return(0); + } + dest_tkt(); + return(1); +} +#endif /* KERBEROS */ + +pass(passwd) + char *passwd; +{ + char *xpasswd, *salt; + + if (logged_in || askpasswd == 0) { + reply(503, "Login with USER first."); + return; + } + askpasswd = 0; + if ( +#ifdef KERBEROS + !kerb_ok && +#endif /* KERBEROS */ +#ifdef GSSAPI + !gss_ok && +#endif /* GSSAPI */ + !guest) { /* "ftp" is only account allowed no password */ + if (pw == NULL) + salt = "xx"; + else + salt = pw->pw_passwd; +#ifdef __SCO__ + /* SCO does not provide crypt. */ + xpasswd = ""; +#else + xpasswd = crypt(passwd, salt); +#endif +#ifdef KERBEROS + /* null pw_passwd ok if Kerberos password ok */ + if (pw == NULL || + (*pw->pw_passwd && strcmp(xpasswd, pw->pw_passwd) && + !kpass(pw->pw_name, passwd)) || + (!*pw->pw_passwd && !kpass(pw->pw_name, passwd))) { +#else + /* The strcmp does not catch null passwords! */ + if (pw == NULL || *pw->pw_passwd == '\0' || + strcmp(xpasswd, pw->pw_passwd)) { +#endif /* KERBEROS */ + reply(530, "Login incorrect."); + pw = NULL; + if (login_attempts++ >= 5) { + syslog(LOG_NOTICE, + "repeated login failures from %s", + remotehost); + exit(0); + } + return; + } + } + login_attempts = 0; /* this time successful */ + (void) setegid((gid_t)pw->pw_gid); + (void) initgroups(pw->pw_name, pw->pw_gid); + + /* open wtmp before chroot */ + (void)sprintf(ttyline, "ftp%d", getpid()); + logwtmp(ttyline, pw->pw_name, remotehost); + logged_in = 1; + + if (guest) { + /* + * We MUST do a chdir() after the chroot. Otherwise + * the old current directory will be accessible as "." + * outside the new root! + */ + if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) { + reply(550, "Can't set guest privileges."); + goto bad; + } + } else if (chdir(pw->pw_dir) < 0) { + if (chdir("/") < 0) { + reply(530, "User %s: can't change directory to %s.", + pw->pw_name, pw->pw_dir); + goto bad; + } else + lreply(230, "No directory! Logging in with home=/"); + } + if (seteuid((uid_t)pw->pw_uid) < 0) { + reply(550, "Can't set uid."); + goto bad; + } + if (guest) { + reply(230, "Guest login ok, access restrictions apply."); +#ifdef SETPROCTITLE + sprintf(proctitle, "%s: anonymous/%.*s", remotehost, + sizeof(proctitle) - sizeof(remotehost) - + sizeof(": anonymous/"), passwd); + setproctitle(proctitle); +#endif /* SETPROCTITLE */ + if (logging) + syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s, %s", + remotehost, passwd); + } else { + reply(230, "User %s logged in.", pw->pw_name); +#ifdef SETPROCTITLE + sprintf(proctitle, "%s: %s", remotehost, pw->pw_name); + setproctitle(proctitle); +#endif /* SETPROCTITLE */ + if (logging) + syslog(LOG_INFO, "FTP LOGIN FROM %s, %s", + remotehost, pw->pw_name); + } + home = pw->pw_dir; /* home dir for globbing */ + (void) umask(defumask); + return; +bad: + /* Forget all about it... */ + end_login(); +} + +retrieve(cmd, name) + char *cmd, *name; +{ + FILE *fin, *dout; + struct stat st; + int (*closefunc)(); + + if (cmd == 0) { + fin = fopen(name, "r"), closefunc = fclose; + st.st_size = 0; + } else { + char line[FTP_BUFSIZ]; + + (void) sprintf(line, cmd, name), name = line; + fin = ftpd_popen(line, "r"), closefunc = ftpd_pclose; + st.st_size = -1; +#ifndef NOSTBLKSIZE + st.st_blksize = FTP_BUFSIZ; +#endif + } + if (fin == NULL) { + if (errno != 0) + perror_reply(550, name); + return; + } + if (cmd == 0 && + (fstat(fileno(fin), &st) < 0 || (st.st_mode&S_IFMT) != S_IFREG)) { + reply(550, "%s: not a plain file.", name); + goto done; + } + if (restart_point) { + if (type == TYPE_A) { + register int i, n, c; + + n = restart_point; + i = 0; + while (i++ < n) { + if ((c=getc(fin)) == EOF) { + perror_reply(550, name); + goto done; + } + if (c == '\n') + i++; + } + } else if (lseek(fileno(fin), restart_point, L_SET) < 0) { + perror_reply(550, name); + goto done; + } + } + dout = dataconn(name, st.st_size, "w"); + if (dout == NULL) + goto done; +#ifndef NOSTBLKSIZE + send_data(fin, dout, st.st_blksize); +#else + send_data(fin, dout, FTP_BUFSIZ); +#endif + (void) fclose(dout); + data = -1; + pdata = -1; +done: + (*closefunc)(fin); +} + +store(name, mode, unique) + char *name, *mode; + int unique; +{ + FILE *fout, *din; + struct stat st; + int (*closefunc)(); + char *gunique(); + + if (unique && stat(name, &st) == 0 && + (name = gunique(name)) == NULL) + return; + + if (restart_point) + mode = "r+w"; + fout = fopen(name, mode); + closefunc = fclose; + if (fout == NULL) { + perror_reply(553, name); + return; + } + if (restart_point) { + if (type == TYPE_A) { + register int i, n, c; + + n = restart_point; + i = 0; + while (i++ < n) { + if ((c=getc(fout)) == EOF) { + perror_reply(550, name); + goto done; + } + if (c == '\n') + i++; + } + /* + * We must do this seek to "current" position + * because we are changing from reading to + * writing. + */ + if (fseek(fout, 0L, L_INCR) < 0) { + perror_reply(550, name); + goto done; + } + } else if (lseek(fileno(fout), restart_point, L_SET) < 0) { + perror_reply(550, name); + goto done; + } + } + din = dataconn(name, (off_t)-1, "r"); + if (din == NULL) + goto done; + if (receive_data(din, fout) == 0) { + if (unique) + reply(226, "Transfer complete (unique file name:%s).", + name); + else + reply(226, "Transfer complete."); + } + (void) fclose(din); + data = -1; + pdata = -1; +done: + (*closefunc)(fout); +} + +FILE * +getdatasock(mode) + char *mode; +{ + int s, on = 1, tries; + + if (data >= 0) + return (fdopen(data, mode)); + (void) seteuid((uid_t)0); + s = socket(AF_INET, SOCK_STREAM, 0); + if (s < 0) + goto bad; + if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, + (char *) &on, sizeof (on)) < 0) + goto bad; + /* anchor socket to avoid multi-homing problems */ + data_source.sin_family = AF_INET; + data_source.sin_addr = ctrl_addr.sin_addr; + for (tries = 1; ; tries++) { + if (bind(s, (struct sockaddr *)&data_source, + sizeof (data_source)) >= 0) + break; + if (errno != EADDRINUSE || tries > 10) + goto bad; + sleep(tries); + } + (void) seteuid((uid_t)pw->pw_uid); +#ifdef IP_TOS +#ifdef IPTOS_THROUGHPUT + on = IPTOS_THROUGHPUT; + if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0) + syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); +#endif +#endif + return (fdopen(s, mode)); +bad: + (void) seteuid((uid_t)pw->pw_uid); + (void) close(s); + return (NULL); +} + +FILE * +dataconn(name, size, mode) + char *name; + off_t size; + char *mode; +{ + char sizebuf[32]; + FILE *file; + int retry = 0, tos; + + file_size = size; + byte_count = 0; + if (size != (off_t) -1) + (void) sprintf (sizebuf, " (%ld bytes)", size); + else + (void) strcpy(sizebuf, ""); + if (pdata >= 0) { + int s, fromlen = sizeof(data_dest); + + s = accept(pdata, (struct sockaddr *)&data_dest, &fromlen); + if (s < 0) { + reply(425, "Can't open data connection."); + (void) close(pdata); + pdata = -1; + return(NULL); + } + (void) close(pdata); + pdata = s; +#ifdef IP_TOS +#ifdef IPTOS_LOWDELAY + tos = IPTOS_LOWDELAY; + (void) setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, + sizeof(int)); +#endif +#endif + reply(150, "Opening %s mode data connection for %s%s.", + type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf); + return(fdopen(pdata, mode)); + } + if (data >= 0) { + reply(125, "Using existing data connection for %s%s.", + name, sizebuf); + usedefault = 1; + return (fdopen(data, mode)); + } + if (usedefault) + data_dest = his_addr; + usedefault = 1; + file = getdatasock(mode); + if (file == NULL) { + reply(425, "Can't create data socket (%s,%d): %s.", + inet_ntoa(data_source.sin_addr), + ntohs(data_source.sin_port), strerror(errno)); + return (NULL); + } + data = fileno(file); + while (connect(data, (struct sockaddr *)&data_dest, + sizeof (data_dest)) < 0) { + if (errno == EADDRINUSE && retry < swaitmax) { + sleep((unsigned) swaitint); + retry += swaitint; + continue; + } + perror_reply(425, "Can't build data connection"); + (void) fclose(file); + data = -1; + return (NULL); + } + reply(150, "Opening %s mode data connection for %s%s.", + type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf); + return (file); +} + +#ifdef STDARG +secure_error(char *fmt, ...) +#else +/* VARARGS1 */ +secure_error(fmt, p1, p2, p3, p4, p5) + char *fmt; +#endif +{ + char buf[FTP_BUFSIZ]; +#ifdef STDARG + va_list ap; + + va_start(ap, fmt); + vsprintf(buf, fmt, ap); + va_end(ap); +#else + sprintf(buf, fmt, p1, p2, p3, p4, p5); +#endif + reply(535, "%s", buf); + syslog(LOG_ERR, "%s", buf); +} + +/* + * Tranfer the contents of "instr" to + * "outstr" peer using the appropriate + * encapsulation of the data subject + * to Mode, Structure, and Type. + * + * NB: Form isn't handled. + */ +send_data(instr, outstr, blksize) + FILE *instr, *outstr; + off_t blksize; +{ + register int c, cnt; + register char *buf; + int netfd, filefd; + int ret = 0; + + transflag++; + if (setjmp(urgcatch)) { + transflag = 0; + return; + } + switch (type) { + + case TYPE_A: + while ((c = getc(instr)) != EOF) { + byte_count++; + if (c == '\n') { + if (ferror(outstr) || + (ret = secure_putc('\r', outstr)) < 0) + goto data_err; + } + if ((ret = secure_putc(c, outstr)) < 0) + goto data_err; + } + transflag = 0; + if (ferror(instr)) + goto file_err; + if (ferror(outstr) || + (ret = secure_flush(fileno(outstr))) < 0) + goto data_err; + reply(226, "Transfer complete."); + return; + + case TYPE_I: + case TYPE_L: + if ((buf = malloc((u_int)blksize)) == NULL) { + transflag = 0; + perror_reply(451, "Local resource failure: malloc"); + return; + } + netfd = fileno(outstr); + filefd = fileno(instr); + while ((cnt = read(filefd, buf, (u_int)blksize)) > 0 && + (ret = secure_write(netfd, buf, cnt)) == cnt) + byte_count += cnt; + transflag = 0; + (void)free(buf); + if (cnt != 0) { + if (cnt < 0) + goto file_err; + goto data_err; + } + if ((ret = secure_flush(netfd)) < 0) + goto data_err; + reply(226, "Transfer complete."); + return; + default: + transflag = 0; + reply(550, "Unimplemented TYPE %d in send_data", type); + return; + } + +data_err: + transflag = 0; + if (ret != -2) perror_reply(426, "Data connection"); + return; + +file_err: + transflag = 0; + perror_reply(551, "Error on input file"); +} + +/* + * Transfer data from peer to + * "outstr" using the appropriate + * encapulation of the data subject + * to Mode, Structure, and Type. + * + * N.B.: Form isn't handled. + */ +receive_data(instr, outstr) + FILE *instr, *outstr; +{ + register int c; + int cnt, bare_lfs = 0; + char buf[FTP_BUFSIZ]; + int ret = 0; + + transflag++; + if (setjmp(urgcatch)) { + transflag = 0; + return (-1); + } + switch (type) { + + case TYPE_I: + case TYPE_L: + while ((cnt = secure_read(fileno(instr), buf, sizeof buf)) > 0) { + if (write(fileno(outstr), buf, cnt) != cnt) + goto file_err; + byte_count += cnt; + } + transflag = 0; + ret = cnt; + if (cnt < 0) + goto data_err; + return (0); + + case TYPE_E: + reply(553, "TYPE E not implemented."); + transflag = 0; + return (-1); + + case TYPE_A: + while ((c = secure_getc(instr)) >= 0) { + byte_count++; + if (c == '\n') + bare_lfs++; + while (c == '\r') { + if (ferror(outstr)) + goto data_err; + if ((c = secure_getc(instr)) != '\n') { + (void) putc ('\r', outstr); + if (c == '\0') + goto contin2; + } + } + if (c < 0) break; + (void) putc(c, outstr); + contin2: ; + } + fflush(outstr); + ret = c; + if (c == -2 || ferror(instr)) + goto data_err; + if (ferror(outstr)) + goto file_err; + transflag = 0; + if (bare_lfs) { + lreply(226, "WARNING! %d bare linefeeds received in ASCII mode", bare_lfs); + reply(0, " File may not have transferred correctly."); + } + return (0); + default: + reply(550, "Unimplemented TYPE %d in receive_data", type); + transflag = 0; + return (-1); + } + +data_err: + transflag = 0; + if (ret != -2) perror_reply(426, "Data Connection"); + return (-1); + +file_err: + transflag = 0; + perror_reply(452, "Error writing file"); + return (-1); +} + +statfilecmd(filename) + char *filename; +{ + char line[FTP_BUFSIZ]; + FILE *fin; + int c; + char str[FTP_BUFSIZ], *p; + + (void) sprintf(line, "/bin/ls -lgA %s", filename); + fin = ftpd_popen(line, "r"); + lreply(211, "status of %s:", filename); + p = str; + while ((c = getc(fin)) != EOF) { + if (c == '\n') { + if (ferror(stdout)){ + perror_reply(421, "control connection"); + (void) ftpd_pclose(fin); + dologout(1); + /* NOTREACHED */ + } + if (ferror(fin)) { + perror_reply(551, filename); + (void) ftpd_pclose(fin); + return; + } + *p = '\0'; + reply(0, "%s", str); + p = str; + } else *p++ = c; + } + if (p != str) { + *p = '\0'; + reply(0, "%s", str); + } + (void) ftpd_pclose(fin); + reply(211, "End of Status"); +} + +statcmd() +{ + struct sockaddr_in *sin; + u_char *a, *p; + char str[FTP_BUFSIZ]; + + lreply(211, "%s FTP server status:", hostname, version); + reply(0, " %s", version); + sprintf(str, " Connected to %s", remotehost); + if (!isdigit(remotehost[0])) + sprintf(&str[strlen(str)], " (%s)", inet_ntoa(his_addr.sin_addr)); + reply(0, "%s", str); + if (auth_type) reply(0, " Authentication type: %s", auth_type); + if (logged_in) { + if (guest) + reply(0, " Logged in anonymously"); + else + reply(0, " Logged in as %s", pw->pw_name); + } else if (askpasswd) + reply(0, " Waiting for password"); + else if (temp_auth_type) + reply(0, " Waiting for authentication data"); + else + reply(0, " Waiting for user name"); + reply(0, " PROTection level: %s", levelnames[level]); + sprintf(str, " TYPE: %s", typenames[type]); + if (type == TYPE_A || type == TYPE_E) + sprintf(&str[strlen(str)], ", FORM: %s", formnames[form]); + if (type == TYPE_L) +#if 1 + strcat(str, " 8"); +#else +/* this is silly. -- eichin@cygnus.com */ +#if NBBY == 8 + sprintf(&str[strlen(str)], " %d", NBBY); +#else + sprintf(&str[strlen(str)], " %d", bytesize); /* need definition! */ +#endif +#endif + sprintf(&str[strlen(str)], "; STRUcture: %s; transfer MODE: %s", + strunames[stru], modenames[mode]); + reply(0, "%s", str); + if (data != -1) + strcpy(str, " Data connection open"); + else if (pdata != -1) { + strcpy(str, " in Passive mode"); + sin = &pasv_addr; + goto printaddr; + } else if (usedefault == 0) { + strcpy(str, " PORT"); + sin = &data_dest; +printaddr: + a = (u_char *) &sin->sin_addr; + p = (u_char *) &sin->sin_port; +#define UC(b) (((int) b) & 0xff) + sprintf(&str[strlen(str)], " (%d,%d,%d,%d,%d,%d)", UC(a[0]), + UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1])); +#undef UC + } else + strcpy(str, " No data connection"); + reply(0, "%s", str); + reply(211, "End of status"); +} + +fatal(s) + char *s; +{ + reply(451, "Error in server: %s", s); + reply(221, "Closing connection due to server error."); + dologout(0); + /* NOTREACHED */ +} + +char cont_char = ' '; + +#ifdef STDARG +reply(int n, char *fmt, ...) +#else +/* VARARGS2 */ +reply(n, fmt, p0, p1, p2, p3, p4, p5) + int n; + char *fmt; +#endif +{ + char buf[FTP_BUFSIZ]; +#ifdef STDARG + va_list ap; + + va_start(ap, fmt); + vsprintf(buf, fmt, ap); + va_end(ap); +#else + sprintf(buf, fmt, p0, p1, p2, p3, p4, p5); +#endif + + if (auth_type) { + char in[FTP_BUFSIZ], out[FTP_BUFSIZ]; + int length, kerror; + /* + * File protection level also determines whether + * replies are 631 or 632. Should be independent ... + */ + if (n) sprintf(in, "%d%c", n, cont_char); + else in[0] = '\0'; + strcat(in, buf); +#ifdef KERBEROS + if (strcmp(auth_type, "KERBEROS_V4") == 0) + if ((length = level == PROT_P ? + krb_mk_priv((unsigned char *)in, (unsigned char *)out, + strlen(in), schedule, &kdata.session, + &ctrl_addr, &his_addr) + : krb_mk_safe((unsigned char *)in, (unsigned char *)out, + strlen(in), &kdata.session, + &ctrl_addr, &his_addr)) == -1) { + syslog(LOG_ERR, "krb_mk_%s failed for KERBEROS_V4", + level == PROT_P ? "priv" : "safe"); + fputs(in,stdout); + } else +#endif /* KERBEROS */ +#ifdef GSSAPI + /* reply (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; + + in_buf.value = in; + in_buf.length = strlen(in) + 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 */ + secure_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) { + secure_error("GSSAPI didn't encrypt message"); + } else { + 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)) { + syslog(LOG_ERR, "Couldn't encode reply (%s)", + radix_error(kerror)); + fputs(in,stdout); + } else + printf("%s%c%s", level == PROT_P ? "632" : "631", + n ? cont_char : '-', in); + } else { + if (n) printf("%d%c", n, cont_char); + fputs(buf, stdout); + } + printf("\r\n"); + (void)fflush(stdout); + if (debug) { + if (n) syslog(LOG_DEBUG, "<--- %d%c", n, cont_char); + syslog(LOG_DEBUG, "%s", buf); + } +} + +#ifdef STDARG +lreply(int n, char *fmt, ...) +#else +/* VARARGS2 */ +lreply(n, fmt, p0, p1, p2, p3, p4, p5) + int n; + char *fmt; +#endif +{ + char buf[FTP_BUFSIZ]; +#ifdef STDARG + va_list ap; + + va_start(ap, fmt); + vsprintf(buf, fmt, ap); + va_end(ap); +#else + sprintf(buf, fmt, p0, p1, p2, p3, p4, p5); +#endif + cont_char = '-'; + reply(n, "%s", buf); + cont_char = ' '; +} + +ack(s) + char *s; +{ + reply(250, "%s command successful.", s); +} + +nack(s) + char *s; +{ + reply(502, "%s command not implemented.", s); +} + +/* ARGSUSED */ +yyerror(s) + char *s; +{ + char *cp; + + if (cp = strchr(cbuf,'\n')) + *cp = '\0'; + reply(500, "'%s': command not understood.", cbuf); +} + +delete(name) + char *name; +{ + struct stat st; + + if (stat(name, &st) < 0) { + perror_reply(550, name); + return; + } + if ((st.st_mode&S_IFMT) == S_IFDIR) { + if (rmdir(name) < 0) { + perror_reply(550, name); + return; + } + goto done; + } + if (unlink(name) < 0) { + perror_reply(550, name); + return; + } +done: + ack("DELE"); +} + +cwd(path) + char *path; +{ + if (chdir(path) < 0) + perror_reply(550, path); + else + ack("CWD"); +} + +makedir(name) + char *name; +{ + if (mkdir(name, 0777) < 0) + perror_reply(550, name); + else + reply(257, "MKD command successful."); +} + +removedir(name) + char *name; +{ + if (rmdir(name) < 0) + perror_reply(550, name); + else + ack("RMD"); +} + +pwd() +{ + char path[MAXPATHLEN + 1]; + + if (getcwd(path, sizeof path) == (char *)NULL) +#ifdef POSIX + perror_reply(550, path); +#else + reply(550, "%s.", path); +#endif + else + reply(257, "\"%s\" is current directory.", path); +} + +char * +renamefrom(name) + char *name; +{ + struct stat st; + + if (stat(name, &st) < 0) { + perror_reply(550, name); + return ((char *)0); + } + reply(350, "File exists, ready for destination name"); + return (name); +} + +renamecmd(from, to) + char *from, *to; +{ + if (rename(from, to) < 0) + perror_reply(550, "rename"); + else + ack("RNTO"); +} + +dolog(sin) + struct sockaddr_in *sin; +{ + struct hostent *hp = gethostbyaddr((char *)&sin->sin_addr, + sizeof (struct in_addr), AF_INET); + time_t t, time(); + extern char *ctime(); + + if (hp) + (void) strncpy(remotehost, hp->h_name, sizeof (remotehost)); + else + (void) strncpy(remotehost, inet_ntoa(sin->sin_addr), + sizeof (remotehost)); +#ifdef SETPROCTITLE + sprintf(proctitle, "%s: connected", remotehost); + setproctitle(proctitle); +#endif /* SETPROCTITLE */ + + if (logging) { + t = time((time_t *) 0); + syslog(LOG_INFO, "connection from %s at %s", + remotehost, ctime(&t)); + } +} + +/* + * Record logout in wtmp file + * and exit with supplied status. + */ +dologout(status) + int status; +{ + if (logged_in) { + (void) seteuid((uid_t)0); + logwtmp(ttyline, "", ""); + } + /* beware of flushing buffers after a SIGPIPE */ + _exit(status); +} + +void +myoob() +{ + char *cp, *cs; + extern char *strpbrk(); + + /* only process if transfer occurring */ + if (!transflag) + return; + cp = tmpline; + if (getline(cp, sizeof(tmpline), stdin) == NULL) { + reply(221, "You could at least say goodbye."); + dologout(0); + } + upper(cp); + if ((cs = strpbrk(cp, "\r\n"))) + *cs++ = '\0'; + if (strcmp(cp, "ABOR") == 0) { + tmpline[0] = '\0'; + reply(426, "Transfer aborted. Data connection closed."); + reply(226, "Abort successful"); + longjmp(urgcatch, 1); + } + if (strcmp(cp, "STAT") == 0) { + if (file_size != (off_t) -1) + reply(213, "Status: %lu of %lu bytes transferred", + byte_count, file_size); + else + reply(213, "Status: %lu bytes transferred", byte_count); + } +} + +/* + * Note: a response of 425 is not mentioned as a possible response to + * the PASV command in RFC959. However, it has been blessed as + * a legitimate response by Jon Postel in a telephone conversation + * with Rick Adams on 25 Jan 89. + */ +passive() +{ + int len; + register char *p, *a; + + pdata = socket(AF_INET, SOCK_STREAM, 0); + if (pdata < 0) { + perror_reply(425, "Can't open passive connection"); + return; + } + pasv_addr = ctrl_addr; + pasv_addr.sin_port = 0; + (void) seteuid((uid_t)0); + if (bind(pdata, (struct sockaddr *)&pasv_addr, sizeof(pasv_addr)) < 0) { + (void) seteuid((uid_t)pw->pw_uid); + goto pasv_error; + } + (void) seteuid((uid_t)pw->pw_uid); + len = sizeof(pasv_addr); + if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0) + goto pasv_error; + if (listen(pdata, 1) < 0) + goto pasv_error; + a = (char *) &pasv_addr.sin_addr; + p = (char *) &pasv_addr.sin_port; + +#define UC(b) (((int) b) & 0xff) + + reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]), + UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1])); + return; + +pasv_error: + (void) close(pdata); + pdata = -1; + perror_reply(425, "Can't open passive connection"); + return; +} + +/* + * Generate unique name for file with basename "local". + * The file named "local" is already known to exist. + * Generates failure reply on error. + */ +char * +gunique(local) + char *local; +{ + static char new[MAXPATHLEN]; + struct stat st; + char *cp = strrchr(local, '/'); + int count = 0; + + if (cp) + *cp = '\0'; + if (stat(cp ? local : ".", &st) < 0) { + perror_reply(553, cp ? local : "."); + return((char *) 0); + } + if (cp) + *cp = '/'; + (void) strcpy(new, local); + cp = new + strlen(new); + *cp++ = '.'; + for (count = 1; count < 100; count++) { + (void) sprintf(cp, "%d", count); + if (stat(new, &st) < 0) + return(new); + } + reply(452, "Unique file name cannot be created."); + return((char *) 0); +} + +/* + * Format and send reply containing system error number. + */ +perror_reply(code, string) + int code; + char *string; +{ + reply(code, "%s: %s.", string, strerror(errno)); +} + +auth(type) +char *type; +{ + if (auth_type) + reply(534, "Authentication type already set to %s", auth_type); + else +#ifdef KERBEROS + if (strcmp(type, "KERBEROS_V4") == 0) + reply(334, "Using authentication type %s; ADAT must follow", + temp_auth_type = type); + else +#endif /* KERBEROS */ +#ifdef GSSAPI + if (strcmp(type, "GSSAPI") == 0) + reply(334, "Using authentication type %s; ADAT must follow", + temp_auth_type = type); + else +#endif /* KERBEROS */ + /* Other auth types go here ... */ + reply(504, "Unknown authentication type: %s", type); +} + +auth_data(data) +char *data; +{ + int kerror, length; +#ifdef KERBEROS + int i; + static char *service; + char instance[INST_SZ]; + u_long cksum; + char buf[FTP_BUFSIZ]; + u_char out_buf[sizeof(buf)]; +#endif /* KERBEROS */ +#ifdef GSSAPI + OM_uint32 maj_stat, min_stat; + gss_OID mechid; + gss_buffer_desc tok, out_tok; + char gbuf[FTP_BUFSIZ]; + u_char gout_buf[sizeof(gbuf)]; +#endif + + if (auth_type) { + reply(503, "Authentication already established"); + return(0); + } + if (!temp_auth_type) { + reply(503, "Must identify AUTH type before ADAT"); + return(0); + } +#ifdef KERBEROS + if (strcmp(temp_auth_type, "KERBEROS_V4") == 0) { + if (kerror = radix_encode(data, out_buf, &length, 1)) { + reply(501, "Couldn't decode ADAT (%s)", + radix_error(kerror)); + syslog(LOG_ERR, "Couldn't decode ADAT (%s)", + radix_error(kerror)); + return(0); + } + (void) memcpy((char *)ticket.dat, (char *)out_buf, ticket.length = length); + strcpy(instance, "*"); + if (!service) { + char realm[REALM_SZ]; + des_cblock key; + + service = "ftp"; + if (krb_get_lrealm(realm, 1) == KSUCCESS && + read_service_key(service, instance, realm, 0, keyfile, key)) + service = "rcmd"; + else (void) memset(key, 0, sizeof(key)); + } + if (kerror = krb_rd_req(&ticket, service, instance, + his_addr.sin_addr.s_addr, &kdata, keyfile)) { + secure_error("ADAT: Kerberos V4 krb_rd_req: %s", + krb_get_err_text(kerror)); + return(0); + } + /* add one to the (formerly) sealed checksum, and re-seal it */ + cksum = kdata.checksum + 1; + cksum = htonl(cksum); + key_sched(kdata.session,schedule); + if ((length = krb_mk_safe((u_char *)&cksum, out_buf, sizeof(cksum), + &kdata.session,&ctrl_addr, &his_addr)) == -1) { + secure_error("ADAT: krb_mk_safe failed"); + return(0); + } + if (kerror = radix_encode(out_buf, buf, &length, 0)) { + secure_error("Couldn't encode ADAT reply (%s)", + radix_error(kerror)); + return(0); + } + reply(235, "ADAT=%s", buf); + /* Kerberos V4 authentication succeeded */ + auth_type = temp_auth_type; + temp_auth_type = NULL; + return(1); + } +#endif /* KERBEROS */ +#ifdef GSSAPI + if (strcmp(temp_auth_type, "GSSAPI") == 0) { + int replied = 0; + gss_cred_id_t server_creds; + gss_name_t client; + int ret_flags; + struct gss_channel_bindings_struct chan; + gss_buffer_desc name_buf; + gss_name_t server_name; + OM_uint32 maj_stat, min_stat; + char localname[MAXHOSTNAMELEN]; + char service_name[MAXHOSTNAMELEN+10]; + char **service; + + chan.initiator_addrtype = GSS_C_AF_INET; + chan.initiator_address.length = 4; + chan.initiator_address.value = &his_addr.sin_addr.s_addr; + chan.acceptor_addrtype = GSS_C_AF_INET; + chan.acceptor_address.length = 4; + chan.acceptor_address.value = &ctrl_addr.sin_addr.s_addr; + chan.application_data.length = 0; + chan.application_data.value = 0; + + if (kerror = radix_encode(data, gout_buf, &length, 1)) { + reply(501, "Couldn't decode ADAT (%s)", + radix_error(kerror)); + syslog(LOG_ERR, "Couldn't decode ADAT (%s)", + radix_error(kerror)); + return(0); + } + tok.value = gout_buf; + tok.length = length; + + if (gethostname(localname, MAXHOSTNAMELEN)) { + reply(501, "couldn't get local hostname (%d)\n", errno); + syslog(LOG_ERR, "Couldn't get local hostname (%d)", errno); + return 0; + } + + for (service = gss_services; *service; service++) { + sprintf(service_name, "%s@%s", *service, localname); + name_buf.value = service_name; + name_buf.length = strlen(name_buf.value) + 1; + if (debug) syslog(LOG_INFO, "importing <%s>", service_name); + maj_stat = gss_import_name(&min_stat, &name_buf, + gss_nt_service_name, + &server_name); + if (maj_stat != GSS_S_COMPLETE) { + reply_gss_error(501, maj_stat, min_stat, + "importing name"); + syslog(LOG_ERR, "gssapi error importing name"); + return 0; + } + + maj_stat = gss_acquire_cred(&min_stat, server_name, 0, + GSS_C_NULL_OID_SET, GSS_C_ACCEPT, + &server_creds, NULL, NULL); + if (maj_stat != GSS_S_COMPLETE) { + reply_gss_error(501, maj_stat, min_stat, + "acquiring credentials"); + syslog(LOG_ERR, "gssapi error acquiring credentials"); + return 0; + } + if (server_creds == GSS_C_NO_CREDENTIAL) { + syslog(LOG_ERR, "acquire return GSS_C_NO_CREDENTIAL"); + } + (void) gss_release_name(&min_stat, &server_name); + break; + } + + gcontext = GSS_C_NO_CONTEXT; + + maj_stat = gss_accept_sec_context(&min_stat, + &gcontext, /* context_handle */ + server_creds, /* verifier_cred_handle */ + &tok, /* input_token */ + &chan, /* channel bindings */ + &client, /* src_name */ + &mechid, /* mech_type */ + &out_tok, /* output_token */ + &ret_flags, + NULL, /* ignore time_rec */ + NULL /* ignore del_cred_handle */ + ); + if (maj_stat!=GSS_S_COMPLETE && maj_stat!=GSS_S_CONTINUE_NEEDED) { + reply_gss_error(535, maj_stat, min_stat, + "accepting context"); + syslog(LOG_ERR, "failed accepting context"); + (void) gss_release_cred(&min_stat, &server_creds); + return 0; + } + + if (out_tok.length) { + if (kerror = radix_encode(out_tok.value, gbuf, &out_tok.length, 0)) { + secure_error("Couldn't encode ADAT reply (%s)", + radix_error(kerror)); + syslog(LOG_ERR, "couldn't encode ADAT reply"); + return(0); + } + if (maj_stat == GSS_S_COMPLETE) { + reply(235, "ADAT=%s", gbuf); + replied = 1; + } else { + /* If the server accepts the security data, and + requires additional data, it should respond with + reply code 335. */ + reply(335, "ADAT=%s", gbuf); + } + (void) gss_release_buffer(&min_stat, &out_tok); + } + if (maj_stat == GSS_S_COMPLETE) { + /* GSSAPI authentication succeeded */ + maj_stat = gss_display_name(&min_stat, client, &client_name, + &mechid); + if (maj_stat != GSS_S_COMPLETE) { + /* "If the server rejects the security data (if + a checksum fails, for instance), it should + respond with reply code 535." */ + reply_gss_error(535, maj_stat, min_stat, + "extracting GSSAPI identity name"); + syslog(LOG_ERR, "gssapi error extracting identity"); + (void) gss_release_cred(&min_stat, &server_creds); + return 0; + } + /* If the server accepts the security data, but does + not require any additional data (i.e., the security + data exchange has completed successfully), it must + respond with reply code 235. */ + if (!replied) reply(235, "GSSAPI Authentication succeeded"); + + auth_type = temp_auth_type; + temp_auth_type = NULL; + + (void) gss_release_cred(&min_stat, &server_creds); + return(1); + } else if (maj_stat == GSS_S_CONTINUE_NEEDED) { + /* If the server accepts the security data, and + requires additional data, it should respond with + reply code 335. */ + reply(335, "more data needed"); + (void) gss_release_cred(&min_stat, &server_creds); + return(0); + } else { + /* "If the server rejects the security data (if + a checksum fails, for instance), it should + respond with reply code 535." */ + reply_gss_error(535, maj_stat, min_stat, + "GSSAPI failed processing ADAT"); + syslog(LOG_ERR, "GSSAPI failed prossing ADAT"); + (void) gss_release_cred(&min_stat, &server_creds); + return(0); + } + } +#endif /* GSSAPI */ + /* Other auth types go here ... */ + /* Also need to check authorization, but that is done in user() */ +} + +static char *onefile[] = { + "", + 0 +}; + +/* returns: + * n>=0 on success + * -1 on error + * -2 on security error + */ +secure_fprintf(stream, fmt, p1, p2, p3, p4, p5) +FILE *stream; +char *fmt; +{ + char s[FTP_BUFSIZ]; + + if (level == PROT_C) + return(fprintf(stream, fmt, p1, p2, p3, p4, p5)); + sprintf(s, fmt, p1, p2, p3, p4, p5); + return(secure_write(fileno(stream), s, strlen(s))); +} + +send_file_list(whichfiles) + char *whichfiles; +{ + struct stat st; + DIR *dirp = NULL; + struct dirent *dir; + FILE *dout = NULL; + register char **dirlist, *dirname; + int simple = 0; + char *strpbrk(); + int ret = 0; + + if (strpbrk(whichfiles, "~{[*?") != NULL) { + extern char **ftpglob(), *globerr; + + globerr = NULL; + dirlist = ftpglob(whichfiles); + if (globerr != NULL) { + reply(550, globerr); + return; + } else if (dirlist == NULL) { + errno = ENOENT; + perror_reply(550, whichfiles); + return; + } + } else { + onefile[0] = whichfiles; + dirlist = onefile; + simple = 1; + } + + if (setjmp(urgcatch)) { + transflag = 0; + return; + } + while (dirname = *dirlist++) { + if (stat(dirname, &st) < 0) { + /* + * If user typed "ls -l", etc, and the client + * used NLST, do what the user meant. + */ + if (dirname[0] == '-' && *dirlist == NULL && + transflag == 0) { + retrieve("/bin/ls %s", dirname); + return; + } + perror_reply(550, whichfiles); + if (dout != NULL) { + (void) fclose(dout); + transflag = 0; + data = -1; + pdata = -1; + } + return; + } + + if ((st.st_mode&S_IFMT) == S_IFREG) { + if (dout == NULL) { + dout = dataconn("file list", (off_t)-1, "w"); + if (dout == NULL) + return; + transflag++; + } + if ((ret = secure_fprintf(dout, "%s%s\n", dirname, + type == TYPE_A ? "\r" : "")) < 0) + goto data_err; + byte_count += strlen(dirname) + 1; + continue; + } else if ((st.st_mode&S_IFMT) != S_IFDIR) + continue; + + if ((dirp = opendir(dirname)) == NULL) + continue; + + while ((dir = readdir(dirp)) != NULL) { + char nbuf[MAXPATHLEN]; + + if (dir->d_name[0] == '.' && dir->d_name[1] == '\0') + continue; + if (dir->d_name[0] == '.' && dir->d_name[1] == '.' && + dir->d_name[2] == '\0') + continue; + + sprintf(nbuf, "%s/%s", dirname, dir->d_name); + + /* + * We have to do a stat to insure it's + * not a directory or special file. + */ + if (simple || (stat(nbuf, &st) == 0 && + (st.st_mode&S_IFMT) == S_IFREG)) { + if (dout == NULL) { + dout = dataconn("file list", (off_t)-1, + "w"); + if (dout == NULL) + return; + transflag++; + } + if (nbuf[0] == '.' && nbuf[1] == '/') + { + if ((ret = secure_fprintf(dout, "%s%s\n", &nbuf[2], + type == TYPE_A ? "\r" : "")) < 0) + goto data_err; + } + else + if ((ret = secure_fprintf(dout, "%s%s\n", nbuf, + type == TYPE_A ? "\r" : "")) < 0) + goto data_err; + byte_count += strlen(nbuf) + 1; + } + } + (void) closedir(dirp); + } + ret = secure_write(fileno(dout), "", 0); +data_err: + if (dout == NULL) + reply(550, "No files found."); + else if (ferror(dout) != 0 || ret == EOF) + perror_reply(550, "Data connection"); + else if (ret != -2) + reply(226, "Transfer complete."); + + transflag = 0; + if (dout != NULL) + (void) fclose(dout); + data = -1; + pdata = -1; +} + +#ifdef SETPROCTITLE +/* + * clobber argv so ps will show what we're doing. + * (stolen from sendmail) + * warning, since this is usually started from inetd.conf, it + * often doesn't have much of an environment or arglist to overwrite. + */ + +setproctitle(buf) +char *buf; +{ + register char *p, *bp, ch; + register int i; + + /* make ps print our process name */ + p = Argv[0]; + *p++ = '-'; + + i = strlen(buf); + if (i > LastArgv - p - 2) { + i = LastArgv - p - 2; + buf[i] = '\0'; + } + bp = buf; + while (ch = *bp++) + if (ch != '\n' && ch != '\r') + *p++ = ch; + while (p < LastArgv) + *p++ = ' '; +} +#endif /* SETPROCTITLE */ +#ifdef GSSAPI +reply_gss_error(code, maj_stat, min_stat, s) +int code; +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)) { + lreply(code, "GSSAPI error major: %s", + (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)) { + lreply(code, "GSSAPI error minor: %s", + (char*)msg.value); + (void) gss_release_buffer(&gmin_stat, &msg); + } + if (gmaj_stat != GSS_S_CONTINUE_NEEDED) + break; + } + reply(code, "GSSAPI error: %s", s); +} + +secure_gss_error(maj_stat, min_stat, s) +OM_uint32 maj_stat, min_stat; +char *s; +{ + return reply_gss_error(535, maj_stat, min_stat, s); +} + + +#include +/* ftpd_userok -- hide details of getting the name and verifying it */ +/* returns 0 for OK */ +ftpd_userok(client_name, name) + gss_buffer_t client_name; + char *name; +{ + int retval = -1; + krb5_boolean k5ret; + krb5_context kc; + krb5_principal p; + krb5_error_code kerr; + krb5_init_context(&kc); + + kerr = krb5_parse_name(kc, client_name->value, &p); + if (kerr) { retval = -1; goto fail; } + k5ret = krb5_kuserok(kc, p, name); + if (k5ret == TRUE) + retval = 0; + else + retval = 1; + krb5_free_principal(kc, p); + fail: + krb5_free_context(kc); + return retval; +} +#endif /* GSSAPI */ diff --git a/src/appl/gssftp/ftpd/logwtmp.c b/src/appl/gssftp/ftpd/logwtmp.c new file mode 100644 index 000000000..36f7e1309 --- /dev/null +++ b/src/appl/gssftp/ftpd/logwtmp.c @@ -0,0 +1,82 @@ +/* + * Copyright (c) 1988 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. + * + */ + +#ifndef lint +static char sccsid[] = "@(#)logwtmp.c 5.7 (Berkeley) 2/25/91"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef WTMP_FILE +#define WTMPFILE WTMP_FILE +#endif + +#ifndef WTMPFILE +#define WTMPFILE "/usr/adm/wtmp" +#endif + +static int fd = -1; + +/* + * Modified version of logwtmp that holds wtmp file open + * after first call, for use with ftp (which may chroot + * after login, but before logout). + */ +logwtmp(line, name, host) + char *line, *name, *host; +{ + struct utmp ut; + struct stat buf; + time_t time(); + + if (fd < 0 && (fd = open(WTMPFILE, O_WRONLY|O_APPEND, 0)) < 0) + return; + if (fstat(fd, &buf) == 0) { + (void)strncpy(ut.ut_line, line, sizeof(ut.ut_line)); + (void)strncpy(ut.ut_name, name, sizeof(ut.ut_name)); +#ifndef NO_UT_HOST + (void)strncpy(ut.ut_host, host, sizeof(ut.ut_host)); +#endif + (void)time(&ut.ut_time); + if (write(fd, (char *)&ut, sizeof(struct utmp)) != + sizeof(struct utmp)) + (void)ftruncate(fd, buf.st_size); + } +} diff --git a/src/appl/gssftp/ftpd/pathnames.h b/src/appl/gssftp/ftpd/pathnames.h new file mode 100644 index 000000000..8669e466a --- /dev/null +++ b/src/appl/gssftp/ftpd/pathnames.h @@ -0,0 +1,36 @@ +/* + * 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 + */ + +#define _PATH_FTPUSERS "/etc/ftpusers" diff --git a/src/appl/gssftp/ftpd/popen.c b/src/appl/gssftp/ftpd/popen.c new file mode 100644 index 000000000..89f29a206 --- /dev/null +++ b/src/appl/gssftp/ftpd/popen.c @@ -0,0 +1,190 @@ +/* + * Copyright (c) 1988 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software written by Ken Arnold and + * published in UNIX Review, Vol. 6, No. 8. + * + * 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[] = "@(#)popen.c 5.9 (Berkeley) 2/25/91"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_VFORK_H +#include +#endif + +/* + * Special version of popen which avoids call to shell. This insures noone + * may create a pipe to a hidden program as a side effect of a list or dir + * command. + */ +static int *pids; +static int fds; + + +FILE * +ftpd_popen(program, type) + char *program, *type; +{ + register char *cp; + FILE *iop; + int argc, gargc, pdes[2], pid; + char **pop, *argv[100], *gargv[1000], *vv[2]; + extern char **ftpglob(), **copyblk(); + + if (*type != 'r' && *type != 'w' || type[1]) + return(NULL); + + if (!pids) { + if ((fds = getdtablesize()) <= 0) + return(NULL); + if ((pids = (int *)malloc((u_int)(fds * sizeof(int)))) == NULL) + return(NULL); + memset((char *)pids, 0, fds * sizeof(int)); + } + if (pipe(pdes) < 0) + return(NULL); + + /* break up string into pieces */ + for (argc = 0, cp = program;; cp = NULL) + if (!(argv[argc++] = strtok(cp, " \t\n"))) + break; + for (argc = 0; argv[argc]; argc++) argv[argc] = strdup(argv[argc]); + + /* glob each piece */ + gargv[0] = argv[0]; + for (gargc = argc = 1; argv[argc]; argc++) { + if (!(pop = ftpglob(argv[argc]))) { /* globbing failed */ + vv[0] = argv[argc]; + vv[1] = NULL; + pop = copyblk(vv); + } + argv[argc] = (char *)pop; /* save to free later */ + while (*pop && gargc < 1000) + gargv[gargc++] = *pop++; + } + gargv[gargc] = NULL; + + iop = NULL; + switch(pid = vfork()) { + case -1: /* error */ + (void)close(pdes[0]); + (void)close(pdes[1]); + goto pfree; + /* NOTREACHED */ + case 0: /* child */ + if (*type == 'r') { + if (pdes[1] != 1) { + dup2(pdes[1], 1); + dup2(pdes[1], 2); /* stderr, too! */ + (void)close(pdes[1]); + } + (void)close(pdes[0]); + } else { + if (pdes[0] != 0) { + dup2(pdes[0], 0); + (void)close(pdes[0]); + } + (void)close(pdes[1]); + } + execv(gargv[0], gargv); + _exit(1); + } + /* parent; assume fdopen can't fail... */ + if (*type == 'r') { + iop = fdopen(pdes[0], type); + (void)close(pdes[1]); + } else { + iop = fdopen(pdes[1], type); + (void)close(pdes[0]); + } + pids[fileno(iop)] = pid; + +pfree: for (argc = 1; argv[argc] != NULL; argc++) { + blkfree((char **)argv[argc]); + free((char *)argv[argc]); + } + return(iop); +} + +ftpd_pclose(iop) + FILE *iop; +{ + register int fdes; +#ifdef USE_SIGPROCMASK + sigset_t old, new; +#else + int omask; +#endif +#ifdef WAIT_USES_INT + int stat_loc; +#else + union wait stat_loc; +#endif + int pid; + + /* + * pclose returns -1 if stream is not associated with a + * `popened' command, or, if already `pclosed'. + */ + if (pids == 0 || pids[fdes = fileno(iop)] == 0) + return(-1); + (void)fclose(iop); +#ifdef USE_SIGPROCMASK + sigemptyset(&old); + sigemptyset(&new); + sigaddset(&new,SIGINT); + sigaddset(&new,SIGQUIT); + sigaddset(&new,SIGHUP); + sigprocmask(SIG_BLOCK, &new, &old); + while ((pid = wait((int *)&stat_loc)) != pids[fdes] && pid != -1); + sigprocmask(SIG_SETMASK, &old, NULL); +#else + omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP)); + while ((pid = wait((int *)&stat_loc)) != pids[fdes] && pid != -1); + sigsetmask(omask); +#endif + pids[fdes] = 0; +#ifdef WAIT_USES_INT + return(pid == -1 ? -1 : stat_loc); +#else + return(pid == -1 ? -1 : stat_loc.w_status); +#endif +} diff --git a/src/appl/gssftp/ftpd/secure.h b/src/appl/gssftp/ftpd/secure.h new file mode 100644 index 000000000..d7344791d --- /dev/null +++ b/src/appl/gssftp/ftpd/secure.h @@ -0,0 +1,4 @@ +#define CRED_DECL extern AUTH_DAT kdata; +#define SESSION &kdata.session +#define myaddr ctrl_addr +#define hisaddr data_dest diff --git a/src/appl/gssftp/ftpd/vers.c b/src/appl/gssftp/ftpd/vers.c new file mode 100644 index 000000000..76846bda7 --- /dev/null +++ b/src/appl/gssftp/ftpd/vers.c @@ -0,0 +1,38 @@ +/*- + * Copyright (c) 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. + */ + +#ifndef lint +static char sccsid[] = "@(#)vers.c 5.1 (Berkeley) 6/24/90"; +#endif /* not lint */ + +char version[] = "Version 5.60"; -- 2.26.2