blob: d8d9ddd8817d7c13cb0bf215399d64aa3b8eb314 [file] [log] [blame]
/* C K C F T P -- FTP Client for C-Kermit */
char *ckftpv = "FTP Client, 8.0.226, 7 Jan 2004";
/*
Authors:
Jeffrey E Altman <jaltman@secure-endpoints.com>
Secure Endpoints Inc., New York City
Frank da Cruz <fdc@columbia.edu>,
The Kermit Project, Columbia University.
Copyright (C) 2000, 2004,
Trustees of Columbia University in the City of New York.
All rights reserved. See the C-Kermit COPYING.TXT file or the
copyright text in the ckcmai.c module for disclaimer and permissions.
Portions of conditionally included code Copyright Regents of the
University of California and The Stanford SRP Authentication Project;
see notices below.
*/
/*
Pending...
. Implement recursive NLST downloads by trying to CD to each filename.
If it works, it's a directory; if not, it's a file -- GET it. But
that won't work with servers like wu-ftpd that don't send directory
names. Recursion with MLSD is done.
. Make syslog entries for session? Files?
. Messages are printed to stdout and stderr in random fashion. We should
either print everything to stdout, or else be systematic about when
to use stderr.
. Implement mail (MAIL, MLFL, MSOM, etc) if any servers support it.
. Adapt to VMS. Big job because of its record-oriented file system.
RMS programmer required. There are probably also some VMS TCP/IP
product-specific wrinkles, e.g. attribute preservation in VMS-to-VMS
transfers using special options for Multinet or other FTP servers
(find out about STRU VMS).
*/
/*
Quick FTP command reference:
RFC765 (1980) and earlier:
MODE S(tream), B(lock), C(ompressed)
STRU F(ILE), R(ECORD), P(AGE)
TYPE A(SCII) <format>, E(BCDIC) <format>, I(MAGE), L(OCAL) <bytesize>
PORT - Port
PASV - Passive mode
USER - User
PASS - Password
ACCT - Account
CWD - Change Working Directory
REIN - Logout but not disconnect
QUIT - Bye
RETR - Retreive
STOR - Store
APPE - Append
ALLO - Allocate
REST - Restart
RNFR - Rename from
RNTO - Rename to
ABOR - Cancel
DELE - Delete
LIST - Directory
NLST - Name List
SITE - Site parameters or commands
STAT - Status
HELP - Help
NOOP - Noop
RFC959 (1985):
CDUP - Change to Parent Directory
SMNT - Structure Mount
STOU - Store Unique
RMD - Remove Directory
MKD - Make Directory
PWD - Print Directory
SYST - System
RFC2389 (1998):
FEAT - List Features (done)
OPTS - Send options (done)
RFC2640 (1999):
LANG - Specify language for messages (not done)
Pending (Internet Drafts):
SIZE - File size (done)
MDTM - File modification date-time (done)
MLST - File name and attribute list (single file) (not done)
MLSD - File list with attributes (multiple files) (done)
MAIL, MLFL, MSOM - mail delivery (not done)
Alphabetical syntax list:
ABOR <CRLF>
ACCT <SP> <account-information> <CRLF>
ALLO <SP> <decimal-integer> [<SP> R <SP> <decimal-integer>] <CRLF>
APPE <SP> <pathname> <CRLF>
CDUP <CRLF>
CWD <SP> <pathname> <CRLF>
DELE <SP> <pathname> <CRLF>
FEAT <CRLF>
HELP [<SP> <string>] <CRLF>
LANG [<SP> <language-tag> ] <CRLF>
LIST [<SP> <pathname>] <CRLF>
MKD <SP> <pathname> <CRLF>
MLSD [<SP> <pathname>] <CRLF>
MLST [<SP> <pathname>] <CRLF>
MODE <SP> <mode-code> <CRLF>
NLST [<SP> <pathname-or-wildcard>] <CRLF>
NOOP <CRLF>
OPTS <SP> <commandname> [ <SP> <command-options> ] <CRLF>
PASS <SP> <password> <CRLF>
PASV <CRLF>
PORT <SP> <host-port> <CRLF>
PWD <CRLF>
QUIT <CRLF>
REIN <CRLF>
REST <SP> <marker> <CRLF>
RETR <SP> <pathname> <CRLF>
RMD <SP> <pathname> <CRLF>
RNFR <SP> <pathname> <CRLF>
RNTO <SP> <pathname> <CRLF>
SITE <SP> <string> <CRLF>
SIZE <SP> <pathname> <CRLF>
SMNT <SP> <pathname> <CRLF>
STAT [<SP> <pathname>] <CRLF>
STOR <SP> <pathname> <CRLF>
STOU <CRLF>
STRU <SP> <structure-code> <CRLF>
SYST <CRLF>
TYPE <SP> <type-code> <CRLF>
USER <SP> <username> <CRLF>
*/
#include "ckcsym.h" /* Standard includes */
#include "ckcdeb.h"
#ifndef NOFTP /* NOFTP = no FTP */
#ifndef SYSFTP /* SYSFTP = use external ftp client */
#ifdef TCPSOCKET /* Build only if TCP/IP included */
#define CKCFTP_C
/* Note: much of the following duplicates what was done in ckcdeb.h */
/* but let's not mess with it unless it causes trouble. */
#ifdef CK_ANSIC
#include <stdarg.h>
#else /* CK_ANSIC */
#include <varargs.h>
#endif /* CK_ANSIC */
#include <signal.h>
#ifdef OS2
#ifdef OS2ONLY
#include <os2.h>
#endif /* OS2ONLY */
#include "ckowin.h"
#include "ckocon.h"
#endif /* OS2 */
#ifndef ZILOG
#ifdef NT
#include <setjmpex.h>
#ifdef NTSIG
extern int TlsIndex;
#endif /* NTSIG */
#else /* NT */
#include <setjmp.h>
#endif /* NT */
#else
#include <setret.h>
#endif /* ZILOG */
#include "ckcsig.h"
#include <sys/stat.h>
#include <ctype.h>
#include <errno.h>
#ifndef NOTIMEH
#include <time.h>
#endif /* NOTIMEH */
#ifndef EPIPE
#define EPIPE 32 /* Broken pipe error */
#endif /* EPIPE */
/* Kermit includes */
#include "ckcasc.h"
#include "ckcker.h"
#include "ckucmd.h"
#include "ckuusr.h"
#include "ckcnet.h" /* Includes ckctel.h */
#include "ckctel.h" /* (then why include it again?) */
#include "ckcxla.h"
/*
How to get the struct timeval definition so we can call select(). The
xxTIMEH symbols are defined in ckcdeb.h, overridden in various makefile
targets. The problem is: maybe we have already included some header file
that defined struct timeval, and maybe we didn't. If we did, we don't want
to include another header file that defines it again or the compilation will
fail. If we didn't, we have to include the header file where it's defined.
But in some cases even that won't work because of strict POSIX constraints
or somesuch, or because this introduces other conflicts (e.g. struct tm
multiply defined), in which case we have to define it ourselves, but this
can work only if we didn't already encounter a definition.
*/
#ifndef DCLTIMEVAL
#ifdef SV68R3V6
#define DCLTIMEVAL
#else
#ifdef SCO234
#define DCLTIMEVAL
#endif /* SCO234 */
#endif /* SV68R3V6 */
#endif /* DCLTIMEVAL */
#ifdef DCLTIMEVAL
/* Also maybe in some places the elements must be unsigned... */
struct timeval {
long tv_sec;
long tv_usec;
};
#ifdef COMMENT
/* Currently we don't use this... */
struct timezone {
int tz_minuteswest;
int tz_dsttime;
};
#endif /* COMMENT */
#else /* !DCLTIMEVAL */
#ifndef NOSYSTIMEH
#ifdef SYSTIMEH
#include <sys/time.h>
#endif /* SYSTIMEH */
#endif /* NOSYSTIMEH */
#ifndef NOSYSTIMEBH
#ifdef SYSTIMEBH
#include <sys/timeb.h>
#endif /* SYSTIMEBH */
#endif /* NOSYSTIMEBH */
#endif /* DCLTIMEVAL */
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif /* HAVE_STDLIB_H */
#ifndef NOSETTIME
#ifdef COMMENT
/* This section moved to ckcdeb.h */
#ifdef POSIX
#define UTIMEH
#else
#ifdef HPUX9
#define UTIMEH
#else
#ifdef OS2
#define SYSUTIMEH
#endif /* OS2 */
#endif /* HPUX9 */
#endif /* POSIX */
#endif /* COMMENT */
#ifdef SYSUTIMEH
#include <sys/utime.h>
#else
#ifdef UTIMEH
#include <utime.h>
#define SYSUTIMEH
#endif /* UTIMEH */
#endif /* SYSUTIMEH */
#endif /* NOSETTIME */
#ifndef SCO_OSR504
#ifdef SELECT_H
#include <sys/select.h>
#endif /* SELECT_H */
#endif /* SCO_OSR504 */
/* select() dialects... */
#ifdef UNIX
#define BSDSELECT /* BSD select() syntax/semantics */
#else
#ifdef OS2 /* OS/2 or Win32 */
#ifdef NT
#define BSDSELECT
#else /* NT */
#define IBMSELECT
#endif /* NT */
#endif /* OS2 */
#endif /* UNIX */
/* Other select() peculiarities */
#ifdef HPUX
#ifndef HPUX10 /* HP-UX 9.xx and earlier */
#ifndef HPUX1100
/* The three interior args to select() are (int *) rather than (fd_set *) */
#ifndef INTSELECT
#define INTSELECT
#endif /* INTSELECT */
#endif /* HPUX1100 */
#endif /* HPUX10 */
#endif /* HPUX */
#ifdef CK_SOCKS /* SOCKS Internet relay package */
#ifdef CK_SOCKS5 /* SOCKS 5 */
#define accept SOCKSaccept
#define bind SOCKSbind
#define connect SOCKSconnect
#define getsockname SOCKSgetsockname
#define listen SOCKSlisten
#else /* Not SOCKS 5 */
#define accept Raccept
#define bind Rbind
#define connect Rconnect
#define getsockname Rgetsockname
#define listen Rlisten
#endif /* CK_SOCKS5 */
#endif /* CK_SOCKS */
#ifndef NOHTTP
extern char * tcp_http_proxy; /* Name[:port] of http proxy server */
extern int tcp_http_proxy_errno;
extern char * tcp_http_proxy_user;
extern char * tcp_http_proxy_pwd;
extern char * tcp_http_proxy_agent;
#define HTTPCPYL 1024
static char proxyhost[HTTPCPYL];
#endif /* NOHTTP */
int ssl_ftp_proxy = 0; /* FTP over SSL/TLS Proxy Server */
/* Feature selection */
#ifndef USE_SHUTDOWN
/*
We don't use shutdown() because (a) we always call it just before close()
so it's redundant and unnecessary, and (b) it introduces a long pause on
some platforms like SV/68 R3.
*/
/* #define USE_SHUTDOWN */
#endif /* USE_SHUTDOWN */
#ifndef NORESEND
#ifndef NORESTART /* Restart / recover */
#ifndef FTP_RESTART
#define FTP_RESTART
#endif /* FTP_RESTART */
#endif /* NORESTART */
#endif /* NORESEND */
#ifndef NOUPDATE /* Update mode */
#ifndef DOUPDATE
#define DOUPDATE
#endif /* DOUPDATE */
#endif /* NOUPDATE */
#ifndef UNICODE /* Unicode required */
#ifndef NOCSETS /* for charset translation */
#define NOCSETS
#endif /* NOCSETS */
#endif /* UNICODE */
#ifndef OS2
#ifndef HAVE_MSECS /* Millisecond timer */
#ifdef UNIX
#ifdef GFTIMER
#define HAVE_MSECS
#endif /* GFTIMER */
#endif /* UNIX */
#endif /* HAVE_MSECS */
#endif /* OS2 */
#ifdef PIPESEND /* PUT from pipe */
#ifndef PUTPIPE
#define PUTPIPE
#endif /* PUTPIPE */
#endif /* PIPESEND */
#ifndef NOSPL /* PUT from array */
#ifndef PUTARRAY
#define PUTARRAY
#endif /* PUTARRAY */
#endif /* NOSPL */
/* Security... */
#ifdef CK_SRP
#define FTP_SRP
#endif /* CK_SRP */
#ifdef CK_KERBEROS
#ifdef KRB4
/*
There is a conflict between the Key Schedule formats used internally
within the standalone MIT KRB4 library and that used by Eric Young
in OpenSSL and his standalone DES library. Therefore, KRB4 FTP AUTH
cannot be supported when either of those two packages are used.
*/
#ifdef KRB524
#define FTP_KRB4
#else /* KRB524 */
#ifndef CK_SSL
#ifndef LIBDES
#define FTP_KRB4
#endif /* LIBDES */
#endif /* CK_SSL */
#endif /* KRB524 */
#endif /* KRB4 */
#ifdef KRB5
#ifndef HEIMDAL
#define FTP_GSSAPI
#endif /* HEIMDAL */
#endif /* KRB5 */
#endif /* CK_KERBEROS */
/* FTP_SECURITY is defined if any of the above is selected */
#ifndef FTP_SECURITY
#ifdef FTP_GSSAPI
#define FTP_SECURITY
#else
#ifdef FTP_KRB4
#define FTP_SECURITY
#else
#ifdef FTP_SRP
#define FTP_SECURITY
#else
#ifdef CK_SSL
#define FTP_SECURITY
#endif /* CK_SSL */
#endif /* FTP_SRP */
#endif /* FTP_KRB4 */
#endif /* FTP_GSSAPI */
#endif /* FTP_SECURITY */
#ifdef CK_DES
#ifdef CK_SSL
#ifndef LIBDES
#define LIBDES
#endif /* LIBDES */
#endif /* CK_SSL */
#endif /* CK_DES */
#ifdef CRYPT_DLL
#ifndef LIBDES
#define LIBDES
#endif /* LIBDES */
#endif /* CRYPT_DLL */
#ifdef FTP_KRB4
#define des_cblock Block
#define des_key_schedule Schedule
#ifdef KRB524
#ifdef NT
#define _WINDOWS
#endif /* NT */
#include "kerberosIV/krb.h"
#else /* KRB524 */
#ifdef SOLARIS
#ifndef sun
/* For some reason lost in history the Makefile Solaris targets have -Usun */
#define sun
#endif /* sun */
#endif /* SOLARIS */
#include "krb.h"
#define krb_get_err_text_entry krb_get_err_text
#endif /* KRB524 */
#endif /* FTP_KRB4 */
#ifdef CK_SSL
#ifdef FTP_KRB4
#ifndef HEADER_DES_H
#define HEADER_DES_H
#endif /* HEADER_DES_H */
#endif /* FTP_KRB4 */
#include "ck_ssl.h"
#endif /* CK_SSL */
#ifdef FTP_SRP
#ifdef HAVE_PWD_H
#include "pwd.h"
#endif /* HAVE_PWD_H */
#include "t_pwd.h"
#include "t_client.h"
#include "krypto.h"
#endif /* FTP_SRP */
#ifdef FTP_GSSAPI
#include <gssapi/gssapi.h>
/*
Need to include the krb5 file, because we're doing manual fallback
from the v2 mech to the v1 mech. Once there's real negotiation,
we can be generic again.
*/
#include <gssapi/gssapi_generic.h>
#include <gssapi/gssapi_krb5.h>
static gss_ctx_id_t gcontext;
#endif /* FTP_GSSAPI */
#ifdef OS2
#ifdef FTP_SRP
#define MAP_KRYPTO
#ifdef SRPDLL
#define MAP_SRP
#endif /* SRPDLL */
#endif /* FTP_SRP */
#ifdef FTP_KRB4
#define MAP_KRB4
#ifdef CK_ENCRYPTION
#define MAP_DES
#endif /* CK_ENCRYPTION */
#endif /* FTP_KRB4 */
#ifdef FTP_GSSAPI
#define MAP_GSSAPI
#define GSS_OIDS
#endif /* FTP_GSSAPI */
#include "ckoath.h"
extern int k95stdout, wherex[], wherey[];
extern unsigned char colorcmd;
#endif /* OS2 */
#ifdef FTP_KRB4
static char ftp_realm[REALM_SZ + 1];
static KTEXT_ST ftp_tkt;
#ifdef OS2
static LEASH_CREDENTIALS ftp_cred;
#else /* OS2 */
static CREDENTIALS ftp_cred;
#endif /* OS2 */
static MSG_DAT ftp_msg_data;
static des_key_schedule ftp_sched;
static int foo[4] = {99,99,99,99};
#endif /* FTP_KRB4 */
/* getreply() function codes */
#define GRF_AUTH 1 /* Reply to AUTH command */
#define GRF_FEAT 2 /* Reply to FEAT command */
/* Operational definitions */
#define DEF_VBM 0 /* Default verbose mode */
/* #define SETVBM */ /* (see getreply) */
#define URL_ONEFILE /* GET, not MGET, for FTP URL */
#define FTP_BUFSIZ 10240 /* Max size for FTP cmds & replies */
#define SRVNAMLEN 32 /* Max length for server type name */
#define PWDSIZ 256
#define PASSBUFSIZ 256
#define PROMPTSIZ 256
#ifndef MGETMAX /* Max operands for MGET command */
#define MGETMAX 1000
#endif /* MGETMAX */
#ifdef FTP_SRP
#define FUDGE_FACTOR 100
#endif /* FTP_SRP */
/*
Amount of growth from cleartext to ciphertext. krb_mk_priv adds this
number bytes. Must be defined for each auth type.
GSSAPI appears to add 52 bytes, but I'm not sure it is a constant--hartmans
3DES requires 56 bytes. Lets use 96 just to be sure.
*/
#ifdef FTP_GSSAPI
#ifndef FUDGE_FACTOR
#define FUDGE_FACTOR 96
#endif /* FUDGE_FACTOR */
#endif /* FTP_GSSAPI */
#ifdef FTP_KRB4
#ifndef FUDGE_FACTOR
#define FUDGE_FACTOR 32
#endif /* FUDGE_FACTOR */
#endif /* FTP_KRB4 */
#ifndef FUDGE_FACTOR /* In case no auth types define it */
#define FUDGE_FACTOR 0
#endif /* FUDGE_FACTOR */
#ifndef MAXHOSTNAMELEN
#define MAXHOSTNAMELEN 64
#endif /* MAXHOSTNAMELEN */
#define MAX_DNS_NAMELEN (15*(MAXHOSTNAMELEN + 1)+1)
/* Fascist compiler toadying */
#ifndef SENDARG2TYPE
#ifdef COMMENT /* Might be needed here and there */
#define SENDARG2TYPE const char *
#else
#define SENDARG2TYPE char *
#endif /* COMMENT */
#endif /* SENDARG2TYPE */
/* Common text messages */
static char *nocx = "?No FTP control connection\n";
static char *fncnam[] = {
"rename", "overwrite", "backup", "append", "discard", "ask", "update",
"dates-differ", ""
};
/* Macro definitions */
/* Used to speed up text-mode PUTs */
#define zzout(fd,c) \
((fd<0)?(-1):((nout>=ucbufsiz)?(zzsend(fd,c)):(ucbuf[nout++]=c)))
#define CHECKCONN() if(!connected){printf(nocx);return(-9);}
/* Externals */
#ifdef CK_URL
extern struct urldata g_url;
#endif /* CK_URL */
#ifdef DYNAMIC
extern char *zinbuffer, *zoutbuffer; /* Regular Kermit file i/o */
#else
extern char zinbuffer[], zoutbuffer[];
#endif /* DYNAMIC */
extern char *zinptr, *zoutptr;
extern int zincnt, zoutcnt, zobufsize, fncact;
#ifdef CK_TMPDIR
extern int f_tmpdir; /* Directory changed temporarily */
extern char savdir[]; /* For saving current directory */
extern char * dldir;
#endif /* CK_TMPDIR */
extern char * rfspec, * sfspec, * srfspec, * rrfspec; /* For WHERE command */
extern xx_strp xxstring;
extern struct keytab onoff[], txtbin[], rpathtab[];
extern int nrpathtab, xfiletype, patterns, gnferror, moving, what, pktnum;
extern int success, nfils, sndsrc, quiet, nopush, recursive, inserver, binary;
extern int filepeek, nscanfile, fsecs, xferstat, xfermode, lastxfer, tsecs;
extern int backgrd, spackets, rpackets, spktl, rpktl, xaskmore, cmd_rows;
extern int nolinks, msgflg, keep;
extern long fsize, ffc, tfc, filcnt, xfsecs, tfcps, cps, oldcps;
#ifdef GFTIMER
extern CKFLOAT fptsecs, fpfsecs, fpxfsecs;
#else
extern long xfsecs;
#endif /* GFTIMER */
extern char filnam[], * filefile, myhost[];
extern char * snd_move, * rcv_move, * snd_rename, * rcv_rename;
extern int g_skipbup, skipbup, sendmode;
extern int g_displa, fdispla, displa;
#ifdef LOCUS
extern int locus, autolocus;
#endif /* LOCUS */
#ifndef NOCSETS
extern int nfilc, dcset7, dcset8, fileorder;
extern struct csinfo fcsinfo[];
extern struct keytab fcstab[];
extern int fcharset;
#endif /* NOCSETS */
extern char sndbefore[], sndafter[], *sndexcept[]; /* Selection criteria */
extern char sndnbefore[], sndnafter[], *rcvexcept[];
extern CHAR feol;
extern long sendstart, sndsmaller, sndlarger, rs_len;
extern char * remdest;
extern int remfile, remappd, rempipe;
#ifndef NOSPL
extern int cmd_quoting;
#ifdef PUTARRAY
extern int sndxlo, sndxhi, sndxin;
extern char sndxnam[];
extern char **a_ptr[]; /* Array pointers */
extern int a_dim[]; /* Array dimensions */
#endif /* PUTARRAY */
#endif /* NOSPL */
#ifndef NOMSEND /* MPUT and ADD SEND-LIST lists */
extern char *msfiles[];
extern int filesinlist;
extern struct filelist * filehead;
extern struct filelist * filetail;
extern struct filelist * filenext;
extern int addlist;
extern char fspec[]; /* Most recent filespec */
extern int fspeclen; /* Length of fspec[] buffer */
#endif /* NOMSEND */
extern int pipesend;
#ifdef PIPESEND
extern char * sndfilter, * rcvfilter;
#endif /* PIPESEND */
#ifdef CKROOT
extern int ckrooterr;
#endif /* CKROOT */
#ifdef KRB4
extern int krb4_autoget;
_PROTOTYP(char * ck_krb4_realmofhost,(char *));
#endif /* KRB4 */
#ifdef KRB5
extern int krb5_autoget;
extern int krb5_d_no_addresses;
_PROTOTYP(char * ck_krb5_realmofhost,(char *));
#endif /* KRB5 */
#ifdef DCMDBUF
extern char *atmbuf; /* Atom buffer (malloc'd) */
extern char *cmdbuf; /* Command buffer (malloc'd) */
extern char *line; /* Big string buffer #1 */
extern char *tmpbuf; /* Big string buffer #2 */
#else
extern char atmbuf[]; /* The same, but static */
extern char cmdbuf[];
extern char line[];
extern char tmpbuf[];
#endif /* DCMDBUF */
extern char * cmarg, * cmarg2, ** cmlist; /* For setting up file lists */
/* Public variables declared here */
#ifdef NOXFER
int ftpget = 1; /* GET/PUT/REMOTE orientation FTP */
#else
int ftpget = 2; /* GET/PUT/REMOTE orientation AUTO */
#endif /* NOXFER */
int ftpcode = -1; /* Last FTP response code */
int ftp_cmdlin = 0; /* FTP invoked from command line */
int ftp_fai = 0; /* FTP failure count */
int ftp_deb = 0; /* FTP debugging */
int ftp_dis = -1; /* FTP display style */
int ftp_log = 1; /* FTP Auto-login */
int sav_log = -1;
int ftp_action = 0; /* FTP action from command line */
int ftp_dates = 1; /* Set file dates from server */
char ftp_reply_str[FTP_BUFSIZ] = ""; /* Last line of previous reply */
char ftp_srvtyp[SRVNAMLEN] = { NUL, NUL }; /* Server's system type */
char ftp_user_host[MAX_DNS_NAMELEN]= ""; /* FTP hostname specified by user */
char * ftp_host = NULL; /* FTP hostname */
char * ftp_logname = NULL; /* FTP username */
char * ftp_rdir = NULL; /* Remote directory from cmdline */
char * ftp_apw = NULL; /* Anonymous password */
/* Definitions and typedefs needed for prototypes */
#define sig_t my_sig_t
#define sigtype SIGTYP
typedef sigtype (*sig_t)();
/* Static global variables */
static char ftpsndbuf[FTP_BUFSIZ+64];
static char * fts_sto = NULL;
static int ftpsndret = 0;
static struct _ftpsnd {
sig_t oldintr, oldintp;
int reply;
int incs,
outcs;
char * cmd, * local, * remote;
int bytes;
int restart;
int xlate;
char * lmode;
} ftpsnd;
/*
This is just a first stab -- these strings should match how the
corresponding FTP servers identify themselves.
*/
#ifdef UNIX
static char * myostype = "UNIX";
#else
#ifdef VMS
/* not yet... */
static char * myostype = "VMS";
#else
#ifdef OS2
#ifdef NT
static char * myostype = "WIN32";
#else
static char * myostype = "OS/2";
#endif /* NT */
#else
static char * myostype = "UNSUPPORTED";
#endif /* OS2 */
#endif /* VMS */
#endif /* UNIX */
static int noinit = 0; /* Don't send REST, STRU, MODE */
static int alike = 0; /* Client/server like platforms */
static int local = 1; /* Shadows Kermit global 'local' */
static int dout = -1; /* Data connection file descriptor */
static int dpyactive = 0; /* Data transfer is active */
static int globaldin = -1; /* Data connection f.d. */
static int out2screen = 0; /* GET output is to screen */
static int forcetype = 0; /* Force text or binary mode */
static int cancelfile = 0; /* File canceled */
static int cancelgroup = 0; /* Group canceled */
static int anonymous = 0; /* Logging in as anonymous */
static int loggedin = 0; /* Logged in (or not) */
static int puterror = 0; /* What to do on PUT error */
static int geterror = 0; /* What to do on GET error */
static int rfrc = 0; /* remote_files() return code */
static int okrestart = 0; /* Server understands REST */
static int printlines = 0; /* getreply()should print data lines */
static int haveurl = 0; /* Invoked by command-line FTP URL */
static int mdtmok = 1; /* Server supports MDTM */
static int sizeok = 1;
static int featok = 1;
static int mlstok = 1;
static int stouarg = 1;
static int typesent = 0;
static int havesigint = 0;
static long havetype = 0;
static long havesize = -1L;
static char * havemdtm = NULL;
static int mgetmethod = 0; /* NLST or MLSD */
static int mgetforced = 0;
static int i, /* j, k, */ x, y, z; /* Volatile temporaries */
static int c0, c1; /* Temp variables for characters */
static char putpath[CKMAXPATH+1] = { NUL, NUL };
static char asnambuf[CKMAXPATH+1] = { NUL, NUL };
#define RFNBUFSIZ 4096 /* Remote filename buffer size */
static unsigned int maxbuf = 0, actualbuf = 0;
static CHAR *ucbuf = NULL;
static int ucbufsiz = 0;
static unsigned int nout = 0; /* Number of chars in ucbuf */
static jmp_buf recvcancel;
static jmp_buf sendcancel;
static jmp_buf ptcancel;
static jmp_buf jcancel;
static int ptabflg = 0;
/* Protection level symbols */
#define FPL_CLR 1 /* Clear */
#define FPL_SAF 2 /* Safe */
#define FPL_PRV 3 /* Private */
#define FPL_CON 4 /* Confidential */
/* Symbols for file types returned by MLST/MLSD */
#define FTYP_FILE 1 /* Regular file */
#define FTYP_DIR 2 /* Directory */
#define FTYP_CDIR 3 /* Current directory */
#define FTYP_PDIR 4 /* Parent directory */
/* File type symbols keyed to the file-type symbols from ckcker.h */
#define FTT_ASC XYFT_T /* ASCII (text) */
#define FTT_BIN XYFT_B /* Binary (image) */
#define FTT_TEN XYFT_X /* TENEX (TOPS-20) */
/* Server feature table - sfttab[0] > 0 means server supports FEAT and OPTS */
static int sfttab[16] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
#define SFT_AUTH 1 /* FTP server feature codes */
#define SFT_LANG 2
#define SFT_MDTM 3
#define SFT_MLST 4
#define SFT_PBSZ 5
#define SFT_PROT 6
#define SFT_REST 7
#define SFT_SIZE 8
#define SFT_TVFS 9
#define SFT_UTF8 10
#define CNV_AUTO 2 /* FTP filename conversion */
#define CNV_CNV 1
#define CNV_LIT 0
/* SET FTP values */
static int /* SET FTP values... */
ftp_aut = 1, /* Auto-authentication */
#ifdef FTP_SECURITY
ftp_cry = 1, /* Auto-encryption */
ftp_cfw = 0, /* Credential forwarding */
#endif /* FTP_SECURITY */
ftp_cpl = FPL_CLR, /* Command protection level */
ftp_dpl = FPL_CLR, /* Data protection level */
#ifdef FTP_PROXY
ftp_prx = 0, /* Use proxy */
#endif /* FTP_PROXY */
sav_psv = -1, /* For saving passive mode */
ftp_psv = 1, /* Passive mode */
ftp_spc = 1, /* Send port commands */
ftp_typ = FTT_ASC, /* Type */
get_auto = 1, /* Automatic type switching for GET */
tenex = 0, /* Type is Tenex */
ftp_usn = 0, /* Unique server names */
ftp_prm = 0, /* Permissions */
ftp_cnv = CNV_AUTO, /* Filename conversion (2 = auto) */
ftp_vbm = DEF_VBM, /* Verbose mode */
ftp_vbx = DEF_VBM, /* Sticky version of same */
ftp_err = 0, /* Error action */
ftp_fnc = -1; /* Filename collision action */
#ifdef CK_SSL
static int ftp_bug_use_ssl_v2 = 0; /* use SSLv2 for AUTH SSL */
#endif /* CK_SSL */
static int
#ifdef NOCSETS
ftp_csr = -1, /* Remote (server) character set */
#else
ftp_csr = FC_UTF8,
#endif /* NOCSETS */
ftp_xla = 0; /* Character-set translation on/off */
int
ftp_csx = -1, /* Remote charset currently in use */
ftp_csl = -1; /* Local charset currently in use */
static int g_ftp_typ = FTT_ASC; /* For saving and restoring ftp_typ */
char * ftp_nml = NULL; /* /NAMELIST */
char * ftp_tmp = NULL; /* Temporary string */
static char * ftp_acc = NULL; /* Account string */
static char * auth_type = NULL; /* Authentication type */
static char * srv_renam = NULL; /* Server-rename string */
FILE * fp_nml = NULL; /* Namelist file pointer */
static int csocket = -1; /* Control socket */
static int connected = 0; /* Connected to FTP server */
static short ftp_port = 0; /* FTP port */
#ifdef FTPHOST
static int hostcmd = 0; /* Has HOST command been sent */
#endif /* FTPHOST */
static int form, mode, stru, bytesize, curtype = FTT_ASC;
static char bytename[8];
/* For parsing replies to FTP server command */
static char *reply_parse, reply_buf[FTP_BUFSIZ], *reply_ptr;
#ifdef FTP_PROXY
static int proxy, unix_proxy
#endif /* FTP_PROXY */
static char pasv[64]; /* Passive-mode port */
static int passivemode = 0;
static int sendport = 0;
static int servertype = 0; /* FTP server's OS type */
static int testing = 0;
static char ftpcmdbuf[FTP_BUFSIZ];
/* Macro definitions */
#define UC(b) ckitoa(((int)b)&0xff)
#define nz(x) ((x) == 0 ? 1 : (x))
/* Command tables and definitions */
#define FTP_ACC 1 /* FTP command keyword codes */
#define FTP_APP 2
#define FTP_CWD 3
#define FTP_CHM 4
#define FTP_CLS 5
#define FTP_DEL 6
#define FTP_DIR 7
#define FTP_GET 8
#define FTP_IDL 9
#define FTP_MDE 10
#define FTP_MDI 11
#define FTP_MGE 12
#define FTP_MKD 13
#define FTP_MOD 14
#define FTP_MPU 15
#define FTP_OPN 16
#define FTP_PUT 17
#define FTP_PWD 18
#define FTP_RGE 19
#define FTP_REN 20
#define FTP_RES 21
#define FTP_HLP 22
#define FTP_RMD 23
#define FTP_STA 24
#define FTP_SIT 25
#define FTP_SIZ 26
#define FTP_SYS 27
#define FTP_UMA 28
#define FTP_GUP 29
#define FTP_USR 30
#define FTP_QUO 31
#define FTP_TYP 32
#define FTP_FEA 33
#define FTP_OPT 34
#define FTP_CHK 35
#define FTP_VDI 36
#define FTP_ENA 37
#define FTP_DIS 38
struct keytab gprtab[] = { /* GET-PUT-REMOTE keywords */
{ "auto", 2, 0 },
{ "ftp", 1, 0 },
{ "kermit", 0, 0 }
};
static struct keytab qorp[] = { /* QUIT or PROCEED keywords */
{ "proceed", 0, 0 }, /* 0 = proceed */
{ "quit", 1, 0 } /* 1 = quit */
};
static struct keytab ftpcmdtab[] = { /* FTP command table */
{ "account", FTP_ACC, 0 },
{ "append", FTP_APP, 0 },
{ "bye", FTP_CLS, 0 },
{ "cd", FTP_CWD, 0 },
{ "cdup", FTP_GUP, 0 },
{ "check", FTP_CHK, 0 },
{ "chmod", FTP_CHM, 0 },
{ "close", FTP_CLS, 0 },
{ "cwd", FTP_CWD, CM_INV },
{ "delete", FTP_MDE, 0 },
{ "directory", FTP_DIR, 0 },
{ "disable", FTP_DIS, 0 },
{ "enable", FTP_ENA, 0 },
{ "features", FTP_FEA, 0 },
{ "get", FTP_GET, 0 },
{ "help", FTP_HLP, 0 },
{ "idle", FTP_IDL, 0 },
{ "login", FTP_USR, CM_INV },
{ "mdelete", FTP_MDE, CM_INV },
{ "mget", FTP_MGE, 0 },
{ "mkdir", FTP_MKD, 0 },
{ "modtime", FTP_MOD, 0 },
{ "mput", FTP_MPU, 0 },
{ "open", FTP_OPN, 0 },
{ "opt", FTP_OPT, CM_INV|CM_ABR },
{ "opts", FTP_OPT, CM_INV },
{ "options", FTP_OPT, 0 },
{ "put", FTP_PUT, 0 },
{ "pwd", FTP_PWD, 0 },
{ "quit", FTP_CLS, CM_INV },
{ "quote", FTP_QUO, 0 },
{ "reget", FTP_RGE, 0 },
{ "rename", FTP_REN, 0 },
{ "reset", FTP_RES, 0 },
{ "rmdir", FTP_RMD, 0 },
{ "send", FTP_PUT, CM_INV },
{ "site", FTP_SIT, 0 },
{ "size", FTP_SIZ, 0 },
{ "status", FTP_STA, 0 },
{ "system", FTP_SYS, 0 },
{ "type", FTP_TYP, 0 },
{ "umask", FTP_UMA, 0 },
{ "up", FTP_GUP, CM_INV },
{ "user", FTP_USR, 0 },
{ "vdirectory",FTP_VDI, 0 },
{ "", 0, 0 }
};
static int nftpcmd = (sizeof(ftpcmdtab) / sizeof(struct keytab)) - 1;
#define OPN_ANO 1 /* FTP OPEN switch codes */
#define OPN_PSW 2
#define OPN_USR 3
#define OPN_ACC 4
#define OPN_ACT 5
#define OPN_PSV 6
#define OPN_TLS 7
#define OPN_NIN 8
#define OPN_NOL 9
#ifdef FTP_SECURITY
#ifdef CK_SSL
#define USETLSTAB
static struct keytab tlstab[] = { /* FTP SSL/TLS switches */
{ "/ssl", OPN_TLS, 0 },
{ "/tls", OPN_TLS, 0 },
{ "", 0, 0 }
};
static int ntlstab = (sizeof(tlstab) / sizeof(struct keytab)) - 1;
#endif /* CK_SSL */
#endif /* FTP_SECURITY */
static struct keytab ftpswitab[] = { /* FTP command switches */
{ "/account", OPN_ACC, CM_ARG },
{ "/active", OPN_ACT, 0 },
{ "/anonymous", OPN_ANO, 0 },
{ "/noinit", OPN_NIN, 0 },
{ "/nologin", OPN_NOL, 0 },
{ "/passive", OPN_PSV, 0 },
{ "/password", OPN_PSW, CM_ARG },
{ "/user", OPN_USR, CM_ARG },
{ "", 0, 0 }
};
static int nftpswi = (sizeof(ftpswitab) / sizeof(struct keytab)) - 1;
/* FTP { ENABLE, DISABLE } items */
#define ENA_FEAT 1
#define ENA_MDTM 2
#define ENA_MLST 3
#define ENA_SIZE 4
#define ENA_AUTH 5
static struct keytab ftpenatab[] = {
{ "AUTH", ENA_AUTH, 0 },
{ "FEAT", ENA_FEAT, 0 },
{ "MDTM", ENA_MDTM, 0 },
{ "ML", ENA_MLST, CM_INV|CM_ABR },
{ "MLS", ENA_MLST, CM_INV|CM_ABR },
{ "MLSD", ENA_MLST, CM_INV },
{ "MLST", ENA_MLST, 0 },
{ "SIZE", ENA_SIZE, 0 },
{ "", 0, 0 }
};
static int nftpena = (sizeof(ftpenatab) / sizeof(struct keytab)) - 1;
/* SET FTP command keyword indices */
#define FTS_AUT 1 /* Autoauthentication */
#define FTS_CRY 2 /* Encryption */
#define FTS_LOG 3 /* Autologin */
#define FTS_CPL 4 /* Command protection level */
#define FTS_CFW 5 /* Credentials forwarding */
#define FTS_DPL 6 /* Data protection level */
#define FTS_DBG 7 /* Debugging */
#define FTS_PSV 8 /* Passive mode */
#define FTS_SPC 9 /* Send port commands */
#define FTS_TYP 10 /* (file) Type */
#define FTS_USN 11 /* Unique server names (for files) */
#define FTS_VBM 12 /* Verbose mode */
#define FTS_ATP 13 /* Authentication type */
#define FTS_CNV 14 /* Filename conversion */
#define FTS_TST 15 /* Test (progress) messages */
#define FTS_PRM 16 /* (file) Permissions */
#define FTS_XLA 17 /* Charset translation */
#define FTS_CSR 18 /* Server charset */
#define FTS_ERR 19 /* Error action */
#define FTS_FNC 20 /* Collision */
#define FTS_SRP 21 /* SRP options */
#define FTS_GFT 22 /* GET automatic file-type switching */
#define FTS_DAT 23 /* Set file dates */
#define FTS_STO 24 /* Server time offset */
#define FTS_APW 25 /* Anonymous password */
#define FTS_DIS 26 /* File-transfer display style */
#define FTS_BUG 27 /* Bug(s) */
/* FTP BUGS */
#define FTB_SV2 1 /* use SSLv2 */
static struct keytab ftpbugtab[] = {
{ "use-ssl-v2", FTB_SV2, 0 }
};
static int nftpbug = (sizeof(ftpbugtab) / sizeof(struct keytab));
/* FTP PUT options (mutually exclusive, not a bitmask) */
#define PUT_UPD 1 /* Update */
#define PUT_RES 2 /* Restart */
#define PUT_SIM 4 /* Simulation */
#define PUT_DIF 8 /* Dates Differ */
static struct keytab ftpcolxtab[] = { /* SET FTP COLLISION options */
#ifndef MAC
{ "append", XYFX_A, 0 }, /* append to old file */
#endif /* MAC */
#ifdef COMMENT
{ "ask", XYFX_Q, 0 }, /* ask what to do (not implemented) */
#endif
{ "backup", XYFX_B, 0 }, /* rename old file */
#ifndef MAC
{ "dates-differ", XYFX_M, 0 }, /* accept if dates differ */
{ "discard", XYFX_D, 0 }, /* don't accept new file */
{ "no-supersede", XYFX_D, CM_INV }, /* ditto (MSK compatibility) */
#endif /* MAC */
{ "overwrite", XYFX_X, 0 }, /* overwrite the old file */
{ "rename", XYFX_R, 0 }, /* rename the incoming file */
#ifndef MAC /* This crashes Mac Kermit. */
{ "update", XYFX_U, 0 }, /* replace if newer */
#endif /* MAC */
{ "", 0, 0 }
};
static int nftpcolx = (sizeof(ftpcolxtab) / sizeof(struct keytab)) - 1;
#ifdef FTP_SECURITY
/* FTP authentication options */
#define FTA_AUTO 0 /* Auto */
#define FTA_SRP 1 /* SRP */
#define FTA_GK5 2 /* Kerberos 5 */
#define FTA_K4 3 /* Kerberos 4 */
#define FTA_SSL 4 /* SSL */
#define FTA_TLS 5 /* TLS */
/* FTP authentication types */
#define FTPATYPS 8
static int ftp_auth_type[FTPATYPS] = {
#ifdef FTP_GSSAPI
FTA_GK5, /* GSSAPI Kerberos 5 */
#endif /* FTP_GK5 */
#ifdef FTP_SRP
FTA_SRP, /* SRP */
#endif /* FTP_SRP */
#ifdef FTP_KRB4
FTA_K4, /* Kerberos 4 */
#endif /* FTP_KRB4 */
#ifdef CK_SSL
FTA_TLS, /* TLS */
FTA_SSL, /* SSL */
#endif /* CK_SSL */
0
};
static struct keytab ftpauth[] = { /* SET FTP AUTHTYPE cmd table */
{ "automatic", FTA_AUTO, CM_INV },
#ifdef FTP_GSSAPI
{ "gssapi-krb5", FTA_GK5, 0 },
#endif /* FTP_GSSAPI */
#ifdef FTP_KRB4
{ "k4", FTA_K4, CM_INV },
#endif /* FTP_KRB4 */
#ifdef FTP_GSSAPI
{ "k5", FTA_GK5, CM_INV },
#endif /* FTP_GSSAPI */
#ifdef FTP_KRB4
{ "kerberos4", FTA_K4, 0 },
#endif /* FTP_KRB4 */
#ifdef FTP_GSSAPI
{ "kerberos5", FTA_GK5, CM_INV },
#endif /* FTP_GSSAPI */
#ifdef FTP_KRB4
{ "kerberos_iv",FTA_K4, CM_INV },
#endif /* FTP_KRB4 */
#ifdef FTP_GSSAPI
{ "kerberos_v", FTA_GK5, CM_INV },
#endif /* FTP_GSSAPI */
#ifdef FTP_KRB4
{ "krb4", FTA_K4, CM_INV },
#endif /* FTP_KRB4 */
#ifdef FTP_GSSAPI
{ "krb5", FTA_GK5, CM_INV },
#endif /* FTP_GSSAPI */
#ifdef FTP_SRP
{ "srp", FTA_SRP, 0 },
#endif /* FTP_SRP */
#ifdef CK_SSL
{ "ssl", FTA_SSL, 0 },
{ "tls", FTA_TLS, 0 },
#endif /* CK_SSL */
{ "", 0, 0 }
};
static int nftpauth = (sizeof(ftpauth) / sizeof(struct keytab)) - 1;
#ifdef FTP_SRP
#define SRP_CIPHER 1
#define SRP_HASH 2
static struct keytab ftpsrp[] = { /* SET FTP SRP command table */
{ "cipher", SRP_CIPHER, 0 },
{ "hash", SRP_HASH, 0 },
{ "", 0, 0 }
};
static int nftpsrp = (sizeof(ftpsrp) / sizeof(struct keytab)) - 1;
#endif /* FTP_SRP */
#endif /* FTP_SECURITY */
static struct keytab ftpset[] = { /* SET FTP commmand table */
{ "anonymous-password", FTS_APW, 0 },
#ifdef FTP_SECURITY
{ "authtype", FTS_ATP, 0 },
{ "autoauthentication", FTS_AUT, 0 },
{ "autoencryption", FTS_CRY, 0 },
#endif /* FTP_SECURITY */
{ "autologin", FTS_LOG, 0 },
{ "bug", FTS_BUG, 0 },
#ifndef NOCSETS
{ "character-set-translation",FTS_XLA, 0 },
#endif /* NOCSETS */
{ "collision", FTS_FNC, 0 },
#ifdef FTP_SECURITY
{ "command-protection-level", FTS_CPL, 0 },
{ "cpl", FTS_CPL, CM_INV },
{ "credential-forwarding", FTS_CFW, 0 },
{ "da", FTS_DAT, CM_INV|CM_ABR },
{ "data-protection-level", FTS_DPL, 0 },
#endif /* FTP_SECURITY */
{ "dates", FTS_DAT, 0 },
{ "debug", FTS_DBG, 0 },
{ "display", FTS_DIS, 0 },
#ifdef FTP_SECURITY
{ "dpl", FTS_DPL, CM_INV },
#endif /* FTP_SECURITY */
{ "error-action", FTS_ERR, 0 },
{ "filenames", FTS_CNV, 0 },
{ "get-filetype-switching", FTS_GFT, 0 },
{ "passive-mode", FTS_PSV, 0 },
{ "pasv", FTS_PSV, CM_INV },
{ "permissions", FTS_PRM, 0 },
{ "progress-messages", FTS_TST, 0 },
{ "send-port-commands", FTS_SPC, 0 },
#ifndef NOCSETS
{ "server-character-set", FTS_CSR, 0 },
#endif /* NOCSETS */
{ "server-time-offset", FTS_STO, 0 },
#ifdef FTP_SRP
{ "srp", FTS_SRP, 0 },
#else
{ "srp", FTS_SRP, CM_INV },
#endif /* FTP_SRP */
{ "type", FTS_TYP, 0 },
{ "unique-server-names", FTS_USN, 0 },
{ "verbose-mode", FTS_VBM, 0 },
{ "", 0, 0 }
};
static int nftpset = (sizeof(ftpset) / sizeof(struct keytab)) - 1;
/*
GET and PUT switches are approximately the same as Kermit GET and SEND,
and use the same SND_xxx definitions, but hijack a couple for FTP use.
Don't just make up new ones, since the number of SND_xxx options must be
known in advance for the switch-parsing arrays.
*/
#define SND_USN SND_PRO /* /UNIQUE instead of /PROTOCOL */
#define SND_PRM SND_PIP /* /PERMISSIONS instead of /PIPES */
#define SND_TEN SND_CAL /* /TENEX instead of /CALIBRATE */
static struct keytab putswi[] = { /* FTP PUT switch table */
{ "/after", SND_AFT, CM_ARG },
#ifdef PUTARRAY
{ "/array", SND_ARR, CM_ARG },
#endif /* PUTARRAY */
{ "/as", SND_ASN, CM_ARG|CM_INV|CM_ABR },
{ "/as-name", SND_ASN, CM_ARG },
{ "/ascii", SND_TXT, CM_INV },
{ "/b", SND_BIN, CM_INV|CM_ABR },
{ "/before", SND_BEF, CM_ARG },
{ "/binary", SND_BIN, 0 },
#ifdef PUTPIPE
{ "/command", SND_CMD, CM_PSH },
#endif /* PUTPIPE */
#ifdef COMMENT
/* This works but it's dangerous */
#ifdef DOUPDATE
{ "/dates-differ", SND_DIF, CM_INV },
#endif /* DOUPDATE */
#endif /* COMMENT */
{ "/delete", SND_DEL, 0 },
#ifdef UNIXOROSK
{ "/dotfiles", SND_DOT, 0 },
#endif /* UNIXOROSK */
{ "/error-action", SND_ERR, CM_ARG },
{ "/except", SND_EXC, CM_ARG },
{ "/filenames", SND_NAM, CM_ARG },
#ifdef PIPESEND
#ifndef NOSPL
{ "/filter", SND_FLT, CM_ARG|CM_PSH },
#endif /* NOSPL */
#endif /* PIPESEND */
#ifdef CKSYMLINK
{ "/followlinks", SND_LNK, 0 },
#endif /* CKSYMLINK */
#ifdef VMS
{ "/image", SND_IMG, 0 },
#else
{ "/image", SND_BIN, CM_INV },
#endif /* VMS */
{ "/larger-than", SND_LAR, CM_ARG },
{ "/listfile", SND_FIL, CM_ARG },
#ifndef NOCSETS
{ "/local-character-set", SND_CSL, CM_ARG },
#endif /* NOCSETS */
#ifdef CK_TMPDIR
{ "/move-to", SND_MOV, CM_ARG },
#endif /* CK_TMPDIR */
{ "/nobackupfiles", SND_NOB, 0 },
#ifdef UNIXOROSK
{ "/nodotfiles", SND_NOD, 0 },
#endif /* UNIXOROSK */
#ifdef CKSYMLINK
{ "/nofollowlinks", SND_NLK, 0 },
#endif /* CKSYMLINK */
{ "/not-after", SND_NAF, CM_ARG },
{ "/not-before", SND_NBE, CM_ARG },
#ifdef UNIX
{ "/permissions", SND_PRM, CM_ARG },
#else
{ "/permissions", SND_PRM, CM_ARG|CM_INV },
#endif /* UNIX */
{ "/quiet", SND_SHH, 0 },
#ifdef FTP_RESTART
{ "/recover", SND_RES, 0 },
#endif /* FTP_RESTART */
#ifdef RECURSIVE
{ "/recursive", SND_REC, 0 },
#endif /* RECURSIVE */
{ "/rename-to", SND_REN, CM_ARG },
#ifdef FTP_RESTART
{ "/restart", SND_RES, CM_INV },
#endif /* FTP_RESTART */
#ifndef NOCSETS
{ "/server-character-set", SND_CSR, CM_ARG },
#endif /* NOCSETS */
{ "/server-rename-to", SND_SRN, CM_ARG },
{ "/simulate", SND_SIM, 0 },
{ "/since", SND_AFT, CM_INV|CM_ARG },
{ "/smaller-than", SND_SMA, CM_ARG },
#ifdef COMMENT
{ "/starting-at", SND_STA, CM_ARG },
#endif /* COMMENT */
#ifdef RECURSIVE
{ "/subdirectories", SND_REC, CM_INV },
#endif /* RECURSIVE */
{ "/tenex", SND_TEN, 0 },
{ "/text", SND_TXT, 0 },
#ifndef NOCSETS
{ "/transparent", SND_XPA, 0 },
#endif /* NOCSETS */
{ "/type", SND_TYP, CM_ARG },
#ifdef DOUPDATE
{ "/update", SND_UPD, 0 },
#endif /* DOUPDATE */
{ "/unique-server-names", SND_USN, 0 },
{ "", 0, 0 }
};
static int nputswi = (sizeof(putswi) / sizeof(struct keytab)) - 1;
static struct keytab getswi[] = { /* FTP [M]GET switch table */
{ "/after", SND_AFT, CM_INV },
{ "/as", SND_ASN, CM_ARG|CM_INV|CM_ABR },
{ "/as-name", SND_ASN, CM_ARG },
{ "/ascii", SND_TXT, CM_INV },
{ "/before", SND_BEF, CM_INV },
{ "/binary", SND_BIN, 0 },
{ "/collision", SND_COL, CM_ARG },
#ifdef PUTPIPE
{ "/command", SND_CMD, CM_PSH },
#endif /* PUTPIPE */
{ "/delete", SND_DEL, 0 },
{ "/error-action", SND_ERR, CM_ARG },
{ "/except", SND_EXC, CM_ARG },
{ "/filenames", SND_NAM, CM_ARG },
#ifdef PIPESEND
#ifndef NOSPL
{ "/filter", SND_FLT, CM_ARG|CM_PSH },
#endif /* NOSPL */
#endif /* PIPESEND */
#ifdef VMS
{ "/image", SND_IMG, 0 },
#else
{ "/image", SND_BIN, CM_INV },
#endif /* VMS */
{ "/larger-than", SND_LAR, CM_ARG },
{ "/listfile", SND_FIL, CM_ARG },
#ifndef NOCSETS
{ "/local-character-set", SND_CSL, CM_ARG },
#endif /* NOCSETS */
{ "/match", SND_PAT, CM_ARG },
{ "/ml", SND_MLS, CM_INV|CM_ABR },
{ "/mls", SND_MLS, CM_INV|CM_ABR },
{ "/mlsd", SND_MLS, 0 },
{ "/mlst", SND_MLS, CM_INV },
#ifdef CK_TMPDIR
{ "/move-to", SND_MOV, CM_ARG },
#endif /* CK_TMPDIR */
{ "/namelist", SND_NML, CM_ARG },
{ "/nlst", SND_NLS, 0 },
{ "/nobackupfiles", SND_NOB, 0 },
{ "/nodotfiles", SND_NOD, 0 },
#ifdef DOUPDATE
{ "/dates-differ", SND_DIF, CM_INV },
#endif /* DOUPDATE */
{ "/not-after", SND_NAF, CM_INV },
{ "/not-before", SND_NBE, CM_INV },
{ "/permissions", SND_PRM, CM_INV },
{ "/quiet", SND_SHH, 0 },
#ifdef FTP_RESTART
{ "/recover", SND_RES, 0 },
#endif /* FTP_RESTART */
#ifdef RECURSIVE
{ "/recursive", SND_REC, 0 },
#endif /* RECURSIVE */
{ "/rename-to", SND_REN, CM_ARG },
#ifdef FTP_RESTART
{ "/restart", SND_RES, CM_INV },
#endif /* FTP_RESTART */
#ifndef NOCSETS
{ "/server-character-set", SND_CSR, CM_ARG },
#endif /* NOCSETS */
{ "/server-rename-to", SND_SRN, CM_ARG },
{ "/smaller-than", SND_SMA, CM_ARG },
#ifdef RECURSIVE
{ "/subdirectories", SND_REC, CM_INV },
#endif /* RECURSIVE */
{ "/text", SND_TXT, 0 },
{ "/tenex", SND_TEN, 0 },
#ifndef NOCSETS
{ "/transparent", SND_XPA, 0 },
#endif /* NOCSETS */
{ "/to-screen", SND_MAI, 0 },
#ifdef DOUPDATE
{ "/update", SND_UPD, CM_INV },
#endif /* DOUPDATE */
{ "", 0, 0 }
};
static int ngetswi = (sizeof(getswi) / sizeof(struct keytab)) - 1;
static struct keytab delswi[] = { /* FTP [M]DELETE switch table */
{ "/error-action", SND_ERR, CM_ARG },
{ "/except", SND_EXC, CM_ARG },
{ "/filenames", SND_NAM, CM_ARG },
{ "/larger-than", SND_LAR, CM_ARG },
{ "/nobackupfiles", SND_NOB, 0 },
#ifdef UNIXOROSK
{ "/nodotfiles", SND_NOD, 0 },
#endif /* UNIXOROSK */
{ "/quiet", SND_SHH, 0 },
#ifdef RECURSIVE
{ "/recursive", SND_REC, 0 },
#endif /* RECURSIVE */
{ "/smaller-than", SND_SMA, CM_ARG },
#ifdef RECURSIVE
{ "/subdirectories", SND_REC, CM_INV },
#endif /* RECURSIVE */
{ "", 0, 0 }
};
static int ndelswi = (sizeof(delswi) / sizeof(struct keytab)) - 1;
static struct keytab fntab[] = { /* Filename conversion keyword table */
{ "automatic", 2, CNV_AUTO },
{ "converted", 1, CNV_CNV },
{ "literal", 0, CNV_LIT }
};
static int nfntab = (sizeof(fntab) / sizeof(struct keytab));
static struct keytab ftptyp[] = { /* SET FTP TYPE table */
{ "ascii", FTT_ASC, 0 },
{ "binary", FTT_BIN, 0 },
{ "tenex", FTT_TEN, 0 },
{ "text", FTT_ASC, CM_INV },
{ "", 0, 0 }
};
static int nftptyp = (sizeof(ftptyp) / sizeof(struct keytab)) - 1;
#ifdef FTP_SECURITY
static struct keytab ftppro[] = { /* SET FTP PROTECTION-LEVEL table */
{ "clear", FPL_CLR, 0 },
{ "confidential", FPL_CON, 0 },
{ "private", FPL_PRV, 0 },
{ "safe", FPL_SAF, 0 },
{ "", 0, 0 }
};
static int nftppro = (sizeof(ftppro) / sizeof(struct keytab)) - 1;
#endif /* FTP_SECURITY */
/* Definitions for FTP from RFC765. */
/* Reply codes */
#define REPLY_PRELIM 1 /* Positive preliminary */
#define REPLY_COMPLETE 2 /* Positive completion */
#define REPLY_CONTINUE 3 /* Positive intermediate */
#define REPLY_TRANSIENT 4 /* Transient negative completion */
#define REPLY_ERROR 5 /* Permanent negative completion */
#define REPLY_SECURE 6 /* Security encoded message */
/* Form codes and names */
#define FORM_N 1 /* Non-print */
#define FORM_T 2 /* Telnet format effectors */
#define FORM_C 3 /* Carriage control (ASA) */
/* Structure codes and names */
#define STRU_F 1 /* File (no record structure) */
#define STRU_R 2 /* Record structure */
#define STRU_P 3 /* Page structure */
/* Mode types and names */
#define MODE_S 1 /* Stream */
#define MODE_B 2 /* Block */
#define MODE_C 3 /* Compressed */
/* Protection levels and names */
#define PROT_C 1 /* Clear */
#define PROT_S 2 /* Safe */
#define PROT_P 3 /* Private */
#define PROT_E 4 /* Confidential */
#ifdef COMMENT /* Not used */
#ifdef FTP_NAMES
char *strunames[] = {"0", "File", "Record", "Page" };
char *formnames[] = {"0", "Nonprint", "Telnet", "Carriage-control" };
char *modenames[] = {"0", "Stream", "Block", "Compressed" };
char *levelnames[] = {"0", "Clear", "Safe", "Private", "Confidential" };
#endif /* FTP_NAMES */
/* 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_REPLY_ERRORS 0x20 /* Block might have errors */
#define BLK_RESTART 0x10 /* Block is Restart Marker */
#define BLK_BYTECOUNT 2 /* Bytes in this block */
#endif /* COMMENT */
#define RADIX_ENCODE 0 /* radix_encode() function codes */
#define RADIX_DECODE 1
/*
The default setpbsz() value in the Unix FTP client is 1<<20 (1MB). This
results in a serious performance degradation due to the increased number
of page faults and the inability to overlap encrypt/decrypt, file i/o, and
network i/o. So instead we set the value to 1<<13 (8K), about half the size
of the typical TCP window. Maybe we should add a command to allow the value
to be changed.
*/
#define DEFAULT_PBSZ 1<<13
/* Prototypes */
_PROTOTYP(int remtxt, (char **) );
_PROTOTYP(char * gskreason, (int) );
_PROTOTYP(static int ftpclose,(void));
_PROTOTYP(static int zzsend, (int, CHAR));
_PROTOTYP(static int getreply,(int,int,int,int,int));
_PROTOTYP(static int radix_encode,(CHAR[], CHAR[], int, int *, int));
_PROTOTYP(static int setpbsz,(unsigned int));
_PROTOTYP(static int recvrequest,(char *,char *,char *,char *,
int,int,char *,int,int,int));
_PROTOTYP(static int ftpcmd,(char *,char *,int,int,int));
_PROTOTYP(static int fts_cpl,(int));
_PROTOTYP(static int fts_dpl,(int));
#ifdef FTP_SECURITY
_PROTOTYP(static int ftp_auth, (void));
#endif /* FTP_SECURITY */
_PROTOTYP(static int ftp_user, (char *, char *, char *));
_PROTOTYP(static int ftp_login, (char *));
_PROTOTYP(static int ftp_reset, (void));
_PROTOTYP(static int ftp_rename, (char *, char *));
_PROTOTYP(static int ftp_umask, (char *));
_PROTOTYP(static int secure_flush, (int));
#ifdef COMMENT
_PROTOTYP(static int secure_putc, (char, int));
#endif /* COMMENT */
_PROTOTYP(static int secure_write, (int, CHAR *, unsigned int));
_PROTOTYP(static int scommand, (char *));
_PROTOTYP(static int secure_putbuf, (int, CHAR *, unsigned int));
_PROTOTYP(static int secure_getc, (int, int));
_PROTOTYP(static int secure_getbyte, (int, int));
_PROTOTYP(static int secure_read, (int, char *, int));
_PROTOTYP(static int initconn, (void));
_PROTOTYP(static int dataconn, (char *));
_PROTOTYP(static int setprotbuf,(unsigned int));
_PROTOTYP(static int sendrequest, (char *, char *, char *, int,int,int,int));
_PROTOTYP(static char * radix_error,(int));
_PROTOTYP(static char * ftp_hookup,(char *, int, int));
_PROTOTYP(static CHAR * remote_files, (int, CHAR *, CHAR *, int));
_PROTOTYP(static VOID mlsreset, (void));
_PROTOTYP(static VOID secure_error, (char *fmt, ...));
_PROTOTYP(static VOID lostpeer, (void));
_PROTOTYP(static VOID cancel_remote, (int));
_PROTOTYP(static VOID changetype, (int, int));
_PROTOTYP(static sigtype cmdcancel, (int));
#ifdef FTP_SRP
_PROTOTYP(static int srp_reset, ());
_PROTOTYP(static int srp_ftp_auth, (char *,char *,char *));
_PROTOTYP(static int srp_put, (CHAR *, CHAR **, int, int *));
_PROTOTYP(static int srp_get, (CHAR **, CHAR **, int *, int *));
_PROTOTYP(static int srp_encode, (int, CHAR *, CHAR *, unsigned int));
_PROTOTYP(static int srp_decode, (int, CHAR *, CHAR *, unsigned int));
_PROTOTYP(static int srp_selcipher, (char *));
_PROTOTYP(static int srp_selhash, (char *));
#endif /* FTP_SRP */
#ifdef FTP_GSSAPI
_PROTOTYP(static void user_gss_error,(OM_uint32, OM_uint32,char *));
#endif /* FTP_GSSAPI */
/* D O F T P A R G -- Do an FTP command-line argument. */
#ifdef FTP_SECURITY
#ifndef NOICP
#define FT_NOGSS 1
#define FT_NOK4 2
#define FT_NOSRP 3
#define FT_NOSSL 4
#define FT_NOTLS 5
#define FT_CERTFI 6
#define FT_OKCERT 7
#define FT_DEBUG 8
#define FT_KEY 9
#define FT_SECURE 10
#define FT_VERIFY 11
static struct keytab ftpztab[] = {
{ "!gss", FT_NOGSS, 0 },
{ "!krb4", FT_NOK4, 0 },
{ "!srp", FT_NOSRP, 0 },
{ "!ssl", FT_NOSSL, 0 },
{ "!tls", FT_NOTLS, 0 },
{ "cert", FT_CERTFI, CM_ARG },
{ "certsok", FT_OKCERT, 0 },
{ "debug", FT_DEBUG, 0 },
{ "key", FT_KEY, CM_ARG },
{ "nogss", FT_NOGSS, 0 },
{ "nokrb4", FT_NOK4, 0 },
{ "nosrp", FT_NOSRP, 0 },
{ "nossl", FT_NOSSL, 0 },
{ "notls", FT_NOTLS, 0 },
#ifdef COMMENT
{ "secure", FT_SECURE, 0 },
#endif /* COMMENT */
{ "verify", FT_VERIFY, CM_ARG },
{ "", 0, 0 }
};
static int nftpztab = sizeof(ftpztab) / sizeof(struct keytab) - 1;
/*
The following cipher and hash tables should be replaced with
dynamicly created versions based upon the linked library.
*/
#define SRP_BLOWFISH_ECB 1
#define SRP_BLOWFISH_CBC 2
#define SRP_BLOWFISH_CFB64 3
#define SRP_BLOWFISH_OFB64 4
#define SRP_CAST5_ECB 5
#define SRP_CAST5_CBC 6
#define SRP_CAST5_CFB64 7
#define SRP_CAST5_OFB64 8
#define SRP_DES_ECB 9
#define SRP_DES_CBC 10
#define SRP_DES_CFB64 11
#define SRP_DES_OFB64 12
#define SRP_DES3_ECB 13
#define SRP_DES3_CBC 14
#define SRP_DES3_CFB64 15
#define SRP_DES3_OFB64 16
static struct keytab ciphertab[] = {
{ "blowfish_ecb", SRP_BLOWFISH_ECB, 0 },
{ "blowfish_cbc", SRP_BLOWFISH_CBC, 0 },
{ "blowfish_cfb64", SRP_BLOWFISH_CFB64, 0 },
{ "blowfish_ofb64", SRP_BLOWFISH_OFB64, 0 },
{ "cast5_ecb", SRP_CAST5_ECB, 0 },
{ "cast5_cbc", SRP_CAST5_CBC, 0 },
{ "cast5_cfb64", SRP_CAST5_CFB64, 0 },
{ "cast5_ofb64", SRP_CAST5_OFB64, 0 },
{ "des_ecb", SRP_DES_ECB, 0 },
{ "des_cbc", SRP_DES_CBC, 0 },
{ "des_cfb64", SRP_DES_CFB64, 0 },
{ "des_ofb64", SRP_DES_OFB64, 0 },
{ "des3_ecb", SRP_DES3_ECB, 0 },
{ "des3_cbc", SRP_DES3_CBC, 0 },
{ "des3_cfb64", SRP_DES3_CFB64, 0 },
{ "des3_ofb64", SRP_DES3_OFB64, 0 },
{ "none", 0, 0 },
{ "", 0, 0 }
};
static int nciphertab = sizeof(ciphertab) / sizeof(struct keytab) - 1;
#define SRP_MD5 1
#define SRP_SHA 2
static struct keytab hashtab[] = {
{ "md5", SRP_MD5, 0 },
{ "none", 0, 0 },
{ "sha", SRP_SHA, 0 },
{ "", 0, 0 }
};
static int nhashtab = sizeof(hashtab) / sizeof(struct keytab) - 1;
#endif /* NOICP */
#endif /* FTP_SECURITY */
static char *
strval(s1,s2) char * s1, * s2; {
if (!s1) s1 = "";
if (!s2) s2 = "";
return(*s1 ? s1 : (*s2 ? s2 : "(none)"));
}
#ifndef NOCSETS
static char * rfnptr = NULL;
static int rfnlen = 0;
static char rfnbuf[RFNBUFSIZ]; /* Remote filename translate buffer */
static char * xgnbp = NULL;
static int
strgetc() { /* Helper function for xgnbyte() */
int c;
if (!xgnbp)
return(-1);
if (!*xgnbp)
return(-1);
c = (unsigned) *xgnbp++;
return(((unsigned) c) & 0xff);
}
static int /* Helper function for xpnbyte() */
#ifdef CK_ANSIC
strputc(char c)
#else
strputc(c) char c;
#endif /* CK_ANSIC */
{
rfnlen = rfnptr - rfnbuf;
if (rfnlen >= (RFNBUFSIZ - 1))
return(-1);
*rfnptr++ = c;
*rfnptr = NUL;
return(0);
}
static int
#ifdef CK_ANSIC
xprintc(char c)
#else
xprintc(c) char c;
#endif /* CK_ANSIC */
{
printf("%c",c);
return(0);
}
static VOID
bytswap(c0,c1) int * c0, * c1; {
int t;
t = *c0;
*c0 = *c1;
*c1 = t;
}
#endif /* NOCSETS */
#ifdef CKLOGDIAL
char ftplogbuf[CXLOGBUFL] = { NUL, NUL }; /* Connection Log */
int ftplogactive = 0;
long ftplogprev = 0L;
VOID
ftplogend() {
extern int dialog;
extern char diafil[];
long d1, d2, t1, t2;
char buf[32], * p;
debug(F111,"ftp cx log active",ckitoa(dialog),ftplogactive);
debug(F110,"ftp cx log buf",ftplogbuf,0);
if (!ftplogactive || !ftplogbuf[0]) /* No active record */
return;
ftplogactive = 0; /* Record is not active */
d1 = mjd((char *)ftplogbuf); /* Get start date of this session */
ckstrncpy(buf,ckdate(),31); /* Get current date */
d2 = mjd(buf); /* Convert them to mjds */
p = ftplogbuf; /* Get start time */
p[11] = NUL;
p[14] = NUL; /* Convert to seconds */
t1 = atol(p+9) * 3600L + atol(p+12) * 60L + atol(p+15);
p[11] = ':';
p[14] = ':';
p = buf; /* Get end time */
p[11] = NUL;
p[14] = NUL;
t2 = atol(p+9) * 3600L + atol(p+12) * 60L + atol(p+15);
t2 = ((d2 - d1) * 86400L) + (t2 - t1); /* Compute elapsed time */
if (t2 > -1L) {
ftplogprev = t2;
p = hhmmss(t2);
strncat(ftplogbuf,"E=",CXLOGBUFL); /* Append to log record */
strncat(ftplogbuf,p,CXLOGBUFL);
} else
ftplogprev = 0L;
debug(F101,"ftp cx log dialog","",dialog);
if (dialog) { /* If logging */
int x;
x = diaopn(diafil,1,1); /* Open log in append mode */
if (x > 0) {
debug(F101,"ftp cx log open","",x);
x = zsoutl(ZDIFIL,ftplogbuf); /* Write the record */
debug(F101,"ftp cx log write","",x);
x = zclose(ZDIFIL); /* Close the log */
debug(F101,"ftp cx log close","",x);
}
}
}
VOID
dologftp() {
ftplogend(); /* Previous session not closed out? */
ftplogprev = 0L;
ftplogactive = 1; /* Record is active */
ckmakxmsg(ftplogbuf,CXLOGBUFL,
ckdate()," ",strval(ftp_logname,NULL)," ",ckgetpid(),
" T=FTP N=", strval(ftp_host,NULL)," H=",myhost," ",NULL,NULL);
debug(F110,"ftp cx log begin",ftplogbuf,0);
}
#endif /* CKLOGDIAL */
static char * dummy[2] = { NULL, NULL };
static struct keytab modetab[] = {
{ "active", 0, 0 },
{ "passive", 1, 0 }
};
#ifndef NOCMDL
int /* Called from ckuusy.c */
#ifdef CK_ANSIC
doftparg(char c)
#else
doftparg(c) char c;
#endif /* CK_ANSIC */
/* doftparg */ {
int x, z;
char *xp;
extern char **xargv, *xarg0;
extern int xargc, stayflg, haveftpuid;
extern char uidbuf[];
xp = *xargv+1; /* Pointer for bundled args */
while (c) {
if (ckstrchr("MuDPkcHzm",c)) { /* Options that take arguments */
if (*(xp+1)) {
fatal("?Invalid argument bundling");
}
xargv++, xargc--;
if ((xargc < 1) || (**xargv == '-')) {
fatal("?Required argument missing");
}
}
switch (c) { /* Big switch on arg */
case 'h': /* help */
printf("C-Kermit's FTP client command-line personality. Usage:\n");
printf(" %s [ options ] host [ port ] [-pg files ]\n\n",xarg0);
printf("Options:\n");
printf(" -h = help (this message)\n");
printf(" -m mode = \"passive\" (default) or \"active\"\n");
printf(" -u name = username for autologin (or -M)\n");
printf(" -P password = password for autologin (RISKY)\n");
printf(" -A = autologin anonymously\n");
printf(" -D directory = cd after autologin\n");
printf(" -b = force binary mode\n");
printf(" -a = force text (\"ascii\") mode (or -T)\n");
printf(" -d = debug (double to add timestamps)\n");
printf(" -n = no autologin\n");
printf(" -v = verbose (default)\n");
printf(" -q = quiet\n");
printf(" -S = Stay (issue command prompt when done)\n");
printf(" -Y = do not execute Kermit init file\n");
printf(" -p files = files to put after autologin (or -s)\n");
printf(" -g files = files to get after autologin\n");
printf(" -R = recursive (for use with -p)\n");
#ifdef FTP_SECURITY
printf("\nSecurity options:\n");
printf(" -k realm = Kerberos 4 realm\n");
printf(" -f = Kerboros 5 credentials forwarding\n");
printf(" -x = autoencryption mode\n");
printf(" -c cipher = SRP cipher type\n");
printf(" -H hash = SRP encryption hash\n");
printf(" -z option = Security options\n");
#endif /* FTP_SECURITY */
printf("\n-p or -g, if given, should be last. Example:\n");
printf(" ftp -A kermit.columbia.edu -D kermit -ag TESTFILE\n");
doexit(GOOD_EXIT,-1);
break;
case 'R': /* Recursive */
recursive = 1;
break;
case 'd': /* Debug */
#ifdef DEBUG
if (deblog) {
extern int debtim;
debtim = 1;
} else {
deblog = debopn("debug.log",0);
debok = 1;
}
#endif /* DEBUG */
/* fall thru on purpose */
case 't': /* Trace */
ftp_deb++;
break;
case 'n': /* No autologin */
ftp_log = 0;
break;
case 'i': /* No prompt */
case 'v': /* Verbose */
break; /* (ignored) */
case 'q': /* Quiet */
quiet = 1;
break;
case 'S': /* Stay */
stayflg = 1;
break;
case 'M':
case 'u': /* My User Name */
if ((int)strlen(*xargv) > 63) {
fatal("username too long");
}
ckstrncpy(uidbuf,*xargv,UIDBUFLEN);
haveftpuid = 1;
break;
case 'A':
ckstrncpy(uidbuf,"anonymous",UIDBUFLEN);
haveftpuid = 1;
break;
case 'T': /* Text */
case 'a': /* "ascii" */
case 'b': /* Binary */
binary = (c == 'b') ? FTT_BIN : FTT_ASC;
xfermode = XMODE_M;
filepeek = 0;
patterns = 0;
break;
case 'g': /* Get */
case 'p': /* Put */
case 's': { /* Send (= Put) */
int havefiles, rc;
if (ftp_action) {
fatal("Only one FTP action at a time please");
}
if (*(xp+1)) {
fatal("invalid argument bundling after -s");
}
nfils = 0; /* Initialize file counter */
havefiles = 0; /* Assume nothing to send */
cmlist = xargv + 1; /* Remember this pointer */
while (++xargv, --xargc > 0) { /* Traverse the list */
if (c == 'g') {
havefiles++;
nfils++;
continue;
}
#ifdef RECURSIVE
if (!strcmp(*xargv,".")) {
havefiles = 1;
nfils++;
recursive = 1;
} else
#endif /* RECURSIVE */
if ((rc = zchki(*xargv)) > -1 || (rc == -2)) {
if (rc != -2)
havefiles = 1;
nfils++;
} else if (iswild(*xargv) && nzxpand(*xargv,0) > 0) {
havefiles = 1;
nfils++;
}
}
xargc++, xargv--; /* Adjust argv/argc */
if (!havefiles) {
if (c == 'g') {
fatal("No files to put");
} else {
fatal("No files to get");
}
}
ftp_action = c;
break;
}
case 'D': /* Directory */
makestr(&ftp_rdir,*xargv);
break;
case 'm': /* Mode (Active/Passive */
ftp_psv = lookup(modetab,*xargv,2,NULL);
if (ftp_psv < 0) fatal("Invalid mode");
break;
case 'P':
makestr(&ftp_tmp,*xargv); /* You-Know-What */
break;
case 'Y': /* No initialization file */
break; /* (already done in prescan) */
#ifdef CK_URL
case 'U': { /* URL */
/* These are set by urlparse() - any not set are NULL */
if (g_url.hos) {
/*
Kermit has accepted host:port notation since many years before URLs were
invented. Unfortunately, URLs conflict with this notation. Thus "ftp
host:449" looks like a URL and results in service = host and host = 449.
Here we try to catch this situation transparently to the user.
*/
if (ckstrcmp(g_url.svc,"ftp",-1,0)
#ifdef CK_SSL
&& ckstrcmp(g_url.svc,"ftps",-1,0)
#endif /* CK_SSL */
) {
if (!g_url.usr &&
!g_url.psw &&
!g_url.por &&
!g_url.pth) {
g_url.por = g_url.hos;
g_url.hos = g_url.svc;
g_url.svc = "ftp";
} else {
ckmakmsg(tmpbuf,TMPBUFSIZ,"Non-FTP URL: service=",
g_url.svc," host=",g_url.hos);
fatal(tmpbuf);
}
}
makestr(&ftp_host,g_url.hos);
if (g_url.usr) {
haveftpuid = 1;
ckstrncpy(uidbuf,g_url.usr,UIDBUFLEN);
makestr(&ftp_logname,uidbuf);
}
if (g_url.psw) {
makestr(&ftp_tmp,g_url.psw);
}
if (g_url.pth) {
if (!g_url.usr) {
haveftpuid = 1;
ckstrncpy(uidbuf,"anonymous",UIDBUFLEN);
makestr(&ftp_logname,uidbuf);
}
if (ftp_action) {
fatal("Only one FTP action at a time please");
}
if (!stayflg)
quiet = 1;
nfils = 1;
dummy[0] = g_url.pth;
cmlist = dummy;
ftp_action = 'g';
}
xp = NULL;
haveurl = 1;
}
break;
}
#endif /* CK_URL */
#ifdef FTP_SECURITY
case 'k': { /* K4 Realm */
#ifdef FTP_KRB4
ckstrncpy(ftp_realm,*xargv, REALM_SZ);
#endif /* FTP_KRB4 */
if (ftp_deb) printf("K4 Realm = [%s]\n",*xargv);
break;
}
case 'f': {
#ifdef FTP_GSSAPI
ftp_cfw = 1;
if (ftp_deb) printf("K5 Credentials Forwarding\n");
#else /* FTP_GSSAPI */
printf("K5 Credentials Forwarding not supported\n");
#endif /* FTP_GSSAPI */
break;
}
case 'x': {
ftp_cry = 1;
if (ftp_deb) printf("Autoencryption\n");
break;
}
case 'c': { /* Cipher */
#ifdef FTP_SRP
if (!srp_selcipher(*xargv)) {
if (ftp_deb) printf("SRP cipher type: \"%s\"\n",*xargv);
} else
printf("?Invalid SRP cipher type: \"%s\"\n",*xargv);
#else /* FTP_SRP */
printf("?SRP not supported\n");
#endif /* FTP_SRP */
break;
}
case 'H': {
#ifdef FTP_SRP
if (!srp_selhash(*xargv)) {
if (ftp_deb) printf("SRP hash type: \"%s\"\n",*xargv);
} else
printf("?Invalid SRP hash type: \"%s\"\n",*xargv);
#else /* FTP_SRP */
printf("?SRP not supported\n");
#endif /* FTP_SRP */
break;
}
case 'z': {
/* *xargv contains a value of the form tag=value */
/* we need to lookup the tag and save the value */
char * p = NULL, * q = NULL;
makestr(&p,*xargv);
y = ckindex("=",p,0,0,1);
if (y > 0)
p[y-1] = '\0';
x = lookup(ftpztab,p,nftpztab,&z);
if (x < 0) {
printf("?Invalid security option: \"%s\"\n",p);
} else {
if (ftp_deb)
printf("Security option: \"%s",p);
if (ftpztab[z].flgs & CM_ARG) {
if (y <= 0)
fatal("?Missing required value");
q = &p[y];
if (!*q)
fatal("?Missing required value");
if (ftp_deb)
printf("=%s\"",q);
}
switch (ftpztab[z].kwval) { /* -z options w/args */
case FT_NOGSS:
#ifdef FTP_GSSAPI
for (z = 0; z < FTPATYPS && ftp_auth_type[z]; z++) {
if (ftp_auth_type[z] == FTA_GK5) {
for (y = z;
y < (FTPATYPS-1) && ftp_auth_type[y];
y++
)
ftp_auth_type[y] = ftp_auth_type[y+1];
ftp_auth_type[FTPATYPS-1] = 0;
break;
}
}
#endif /* FTP_GSSAPI */
break;
case FT_NOK4:
#ifdef FTP_KRB4
for (z = 0; z < FTPATYPS && ftp_auth_type[z]; z++) {
if (ftp_auth_type[z] == FTA_K4) {
for (y = z;
y < (FTPATYPS-1) && ftp_auth_type[y];
y++
)
ftp_auth_type[y] = ftp_auth_type[y+1];
ftp_auth_type[FTPATYPS-1] = 0;
break;
}
}
#endif /* FTP_KRB4 */
break;
case FT_NOSRP:
#ifdef FTP_SRP
for (z = 0; z < FTPATYPS && ftp_auth_type[z]; z++) {
if (ftp_auth_type[z] == FTA_SRP) {
for (y = z;
y < (FTPATYPS-1) && ftp_auth_type[y];
y++
)
ftp_auth_type[y] = ftp_auth_type[y+1];
ftp_auth_type[FTPATYPS-1] = 0;
break;
}
}
#endif /* FTP_SRP */
break;
case FT_NOSSL:
#ifdef CK_SSL
for (z = 0; z < FTPATYPS && ftp_auth_type[z]; z++) {
if (ftp_auth_type[z] == FTA_SSL) {
for (y = z;
y < (FTPATYPS-1) && ftp_auth_type[y];
y++
)
ftp_auth_type[y] = ftp_auth_type[y+1];
ftp_auth_type[FTPATYPS-1] = 0;
break;
}
}
#endif /* CK_SSL */
break;
case FT_NOTLS:
#ifdef CK_SSL
for (z = 0; z < FTPATYPS && ftp_auth_type[z]; z++) {
if (ftp_auth_type[z] == FTA_TLS) {
for (y = z;
y < (FTPATYPS-1) && ftp_auth_type[y];
y++
)
ftp_auth_type[y] = ftp_auth_type[y+1];
ftp_auth_type[FTPATYPS-1] = 0;
break;
}
}
#endif /* CK_SSL */
break;
case FT_CERTFI:
#ifdef CK_SSL
makestr(&ssl_rsa_cert_file,q);
#endif /* CK_SSL */
break;
case FT_OKCERT:
#ifdef CK_SSL
ssl_certsok_flag = 1;
#endif /* CK_SSL */
break;
case FT_DEBUG:
#ifdef DEBUG
if (deblog) {
extern int debtim;
debtim = 1;
} else {
deblog = debopn("debug.log",0);
}
#endif /* DEBUG */
break;
case FT_KEY:
#ifdef CK_SSL
makestr(&ssl_rsa_key_file,q);
#endif /* CK_SSL */
break;
case FT_SECURE:
/* no equivalent */
break;
case FT_VERIFY:
#ifdef CK_SSL
if (!rdigits(q))
printf("?Bad number: %s\n",q);
ssl_verify_flag = atoi(q);
#endif /* CK_SSL */
break;
}
}
if (ftp_deb) printf("\"\n");
free(p);
break;
}
#endif /* FTP_SECURITY */
default:
fatal2(*xargv,
"unknown command-line option, type \"ftp -h\" for help"
);
}
if (!xp) break;
c = *++xp; /* See if options are bundled */
}
return(0);
}
#endif /* NOCMDL */
int
ftpisconnected() {
return(connected);
}
int
ftpisloggedin() {
return(connected ? loggedin : 0);
}
int
ftpissecure() {
return((ftp_dpl == FPL_CLR && !ssl_ftp_proxy) ? 0 : 1);
}
static VOID
ftscreen(n, c, z, s) int n; char c; long z; char * s; {
if (displa && fdispla && !backgrd && !quiet && !out2screen) {
if (!dpyactive) {
ckscreen(SCR_PT,'S',0L,"");
dpyactive = 1;
}
ckscreen(n,c,z,s);
}
}
#ifndef OS2
/* g m s t i m e r -- Millisecond timer */
long
gmstimer() {
#ifdef HAVE_MSECS
/* For those versions of ztime() that also set global ztmsec. */
char *p = NULL;
long z;
ztime(&p);
if (!p) return(0L);
if (!*p) return(0L);
z = atol(p+11) * 3600L + atol(p+14) * 60L + atol(p+17);
return(z * 1000 + ztmsec);
#else
return((long)time(NULL) * 1000L);
#endif /* HAVE_MSECS */
}
#endif /* OS2 */
/* d o s e t f t p -- The SET FTP command */
int
dosetftp() {
int cx;
if ((cx = cmkey(ftpset,nftpset,"","",xxstring)) < 0) /* Set what? */
return(cx);
switch (cx) {
case FTS_FNC: /* Filename collision action */
if ((x = cmkey(ftpcolxtab,nftpcolx,"","",xxstring)) < 0)
return(x);
if ((y = cmcfm()) < 0)
return(y);
ftp_fnc = x;
return(1);
case FTS_CNV: /* Filename conversion */
if ((x = cmkey(fntab,nfntab,"","automatic",xxstring)) < 0)
return(x);
if ((y = cmcfm()) < 0)
return(y);
ftp_cnv = x;
return(1);
case FTS_DBG: /* Debug messages */
return(seton(&ftp_deb));
case FTS_LOG: /* Auto-login */
return(seton(&ftp_log));
case FTS_PSV: /* Passive mode */
return(dosetftppsv());
case FTS_SPC: /* Send port commands */
x = seton(&ftp_spc);
if (x > 0) sendport = ftp_spc;
return(x);
case FTS_TYP: /* Type */
if ((x = cmkey(ftptyp,nftptyp,"","",xxstring)) < 0)
return(x);
if ((y = cmcfm()) < 0) return(y);
ftp_typ = x;
g_ftp_typ = x;
tenex = (ftp_typ == FTT_TEN);
return(1);
case FTS_USN: /* Unique server names */
return(seton(&ftp_usn));
case FTS_VBM: /* Verbose mode */
if ((x = seton(&ftp_vbm)) < 0) /* Per-command copy */
return(x);
ftp_vbx = ftp_vbm; /* Global sticky copy */
return(x);
case FTS_TST: /* "if (testing)" messages */
return(seton(&testing));
case FTS_PRM: /* Send permissions */
return(setonaut(&ftp_prm));
case FTS_AUT: /* Auto-authentication */
return(seton(&ftp_aut));
case FTS_ERR: /* Error action */
if ((x = cmkey(qorp,2,"","",xxstring)) < 0)
return(x);
if ((y = cmcfm()) < 0)
return(y);
ftp_err = x;
return(success = 1);
#ifndef NOCSETS
case FTS_XLA: /* Translation */
return(seton(&ftp_xla));
case FTS_CSR: /* Server charset */
if ((x = cmkey(fcstab,nfilc,"character-set","utf8",xxstring)) < 0)
return(x);
if ((y = cmcfm()) < 0)
return(y);
ftp_csr = x;
ftp_xla = 1; /* Also enable translation */
return(success = 1);
#endif /* NOCSETS */
case FTS_GFT:
return(seton(&get_auto)); /* GET-filetype-switching */
case FTS_DAT:
return(seton(&ftp_dates)); /* Set file dates */
case FTS_STO: { /* Server time offset */
char * s, * p = NULL;
int k;
if ((x = cmfld("[+-]hh[:mm[:ss]]","+0",&s,xxstring)) < 0)
return(x);
if (!strcmp(s,"+0")) {
s = NULL;
} else if ((x = delta2sec(s,&k)) < 0) { /* Check format */
printf("?Invalid time offset\n");
return(-9);
}
makestr(&p,s); /* Make a safe copy the string */
if ((x = cmcfm()) < 0) { /* Get confirmation */
if (p)
makestr(&p,NULL);
return(x);
}
fts_sto = p; /* Confirmed - set the string. */
return(success = 1);
}
case FTS_APW: {
char * s;
if ((x = cmtxt("Text", "", &s, xxstring)) < 0)
return(x);
makestr(&ftp_apw, *s ? s : NULL);
return(success = 1);
}
case FTS_BUG: {
if ((x = cmkey(ftpbugtab,nftpbug,"","",xxstring)) < 0)
return(x);
switch (x) {
#ifdef CK_SSL
case FTB_SV2:
return seton(&ftp_bug_use_ssl_v2);
#endif /* CK_SSL */
default:
return(-2);
}
}
#ifdef FTP_SECURITY
case FTS_CRY: /* Auto-encryption */
return(seton(&ftp_cry));
case FTS_CFW: /* Credential-forwarding */
return(seton(&ftp_cfw));
case FTS_CPL: /* Command protection level */
if ((x = cmkey(ftppro,nftppro,"","",xxstring)) < 0) return(x);
if ((y = cmcfm()) < 0) return(y);
success = fts_cpl(x);
return(success);
case FTS_DPL: /* Data protection level */
if ((x = cmkey(ftppro,nftppro,"","",xxstring)) < 0) return(x);
if ((y = cmcfm()) < 0) return(y);
success = fts_dpl(x);
return(success);
case FTS_ATP: { /* FTP Auth Type */
int i, j, atypes[8];
for (i = 0; i < 8; i++) {
if ((y = cmkey(ftpauth,nftpauth,"",
(i == 0) ? "automatic" : "",
xxstring)) < 0) {
if (y == -3)
break;
return(y);
}
if (i > 0 && (y == FTA_AUTO)) {
printf("?Choice may only be used in first position.\r\n");
return(-9);
}
for (j = 0; j < i; j++) {
if (atypes[j] == y) {
printf("\r\n?Choice has already been used.\r\n");
return(-9);
}
}
atypes[i] = y;
if (y == FTA_AUTO) {
i++;
break;
}
}
if (i < 8)
atypes[i] = 0;
if ((z = cmcfm()) < 0)
return(z);
if (atypes[0] == FTA_AUTO) {
i = 0;
#ifdef FTP_GSSAPI
ftp_auth_type[i++] = FTA_GK5;
#endif /* FTP_GSSAPI */
#ifdef FTP_SRP
ftp_auth_type[i++] = FTA_SRP;
#endif /* FTP_SRP */
#ifdef FTP_KRB4
ftp_auth_type[i++] = FTA_K4;
#endif /* FTP_KRB4 */
#ifdef CK_SSL
ftp_auth_type[i++] = FTA_TLS;
ftp_auth_type[i++] = FTA_SSL;
#endif /* CK_SSL */
ftp_auth_type[i] = 0;
} else {
for (i = 0; i < 8; i++)
ftp_auth_type[i] = atypes[i];
}
return(success = 1);
}
case FTS_SRP:
#ifdef FTP_SRP
if ((x = cmkey(ftpsrp,nftpsrp,"","",xxstring)) < 0)
return(x);
switch (x) {
case SRP_CIPHER:
if ((x = cmkey(ciphertab,nciphertab,"","",xxstring)) < 0)
return(x);
if ((z = cmcfm()) < 0)
return(z);
success = !srp_selcipher(ciphertab[x].kwd);
return(success);
case SRP_HASH:
if ((x = cmkey(hashtab,nhashtab,"","",xxstring)) < 0)
return(x);
if ((z = cmcfm()) < 0)
return(z);
success = !srp_selhash(hashtab[x].kwd);
return(success = 1);
default:
if ((z = cmcfm()) < 0)
return(z);
return(-2);
}
#else /* FTP_SRP */
if ((z = cmcfm()) < 0)
return(z);
return(-2);
#endif /* FTP_SRP */
#endif /* FTP_SECURITY */
case FTS_DIS:
doxdis(2); /* 2 == ftp */
return(success = 1);
default:
return(-2);
}
}
int
ftpbye() {
int x;
if (!connected)
return(1);
if (testing)
printf(" ftp closing %s...\n",ftp_host);
x = ftpclose();
return((x > -1) ? 1 : 0);
}
/* o p e n f t p -- Parse FTP hostname & port and open */
static int
openftp(s,opn_tls) char * s; int opn_tls; {
char c, * p, * hostname = NULL, *hostsave = NULL, * service = NULL;
int i, n, havehost = 0, getval = 0, rc = -9, opn_psv = -1, nologin = 0;
int haveuser = 0;
struct FDB sw, fl, cm;
extern int nnetdir; /* Network services directory */
extern int nhcount; /* Lookup result */
extern char *nh_p[]; /* Network directory entry pointers */
extern char *nh_p2[]; /* Network directory entry nettype */
if (!s) return(-2);
if (!*s) return(-2);
makestr(&hostname,s);
hostsave = hostname;
makestr(&ftp_logname,NULL);
anonymous = 0;
noinit = 0;
debug(F110,"ftp open",hostname,0);
if (sav_psv > -1) { /* Restore prevailing active/passive */
ftp_psv = sav_psv; /* selection in case it was */
sav_psv = -1; /* temporarily overriden by a switch */
}
if (sav_log > -1) { /* Ditto for autologin */
ftp_log = sav_log;
sav_log = -1;
}
cmfdbi(&sw, /* Switches */
_CMKEY,
"Service name or port;\n or switch",
"", /* default */
"", /* addtl string data */
nftpswi, /* addtl numeric data 1: tbl size */
4, /* addtl numeric data 2: none */
xxstring, /* Processing function */
ftpswitab, /* Keyword table */
&fl /* Pointer to next FDB */
);
cmfdbi(&fl, /* A host name or address */
_CMFLD, /* fcode */
"", /* help */
"xYzBoo", /* default */
"", /* addtl string data */
0, /* addtl numeric data 1 */
0, /* addtl numeric data 2 */
xxstring,
NULL,
&cm
);
cmfdbi(&cm, /* Command confirmation */
_CMCFM,
"",
"",
"",
0,
0,
NULL,
NULL,
NULL
);
for (n = 0;; n++) {
rc = cmfdb(&sw); /* Parse a service name or a switch */
if (rc < 0)
goto xopenftp;
if (cmresult.fcode == _CMCFM) { /* Done? */
break;
} else if (cmresult.fcode == _CMFLD) { /* Port */
if (ckstrcmp("xYzBoo",cmresult.sresult,-1,1))
makestr(&service,cmresult.sresult);
else
makestr(&service,opn_tls?"ftps":"ftp");
} else if (cmresult.fcode == _CMKEY) { /* Have a switch */
c = cmgbrk(); /* get break character */
getval = (c == ':' || c == '=');
rc = -9;
if (getval && !(cmresult.kflags & CM_ARG)) {
printf("?This switch does not take arguments\n");
goto xopenftp;
}
if (!getval && (cmresult.kflags & CM_ARG)) {
printf("?This switch requires an argument\n");
goto xopenftp;
}
switch (cmresult.nresult) { /* Switch */
case OPN_ANO: /* /ANONYMOUS */
anonymous++;
nologin = 0;
break;
case OPN_NIN: /* /NOINIT */
noinit++;
break;
case OPN_NOL: /* /NOLOGIN */
nologin++;
anonymous = 0;
makestr(&ftp_logname,NULL);
break;
case OPN_PSW: /* /PASSWORD */
if (!anonymous) /* Don't log real passwords */
debok = 0;
rc = cmfld("Password for FTP server","",&p,xxstring);
if (rc == -3) {
makestr(&ftp_tmp,NULL);
} else if (rc < 0) {
goto xopenftp;
} else {
makestr(&ftp_tmp,brstrip(p));
nologin = 0;
}
break;
case OPN_USR: /* /USER */
rc = cmfld("Username for FTP server","",&p,xxstring);
if (rc == -3) {
makestr(&ftp_logname,NULL);
} else if (rc < 0) {
goto xopenftp;
} else {
nologin = 0;
anonymous = 0;
haveuser = 1;
makestr(&ftp_logname,brstrip(p));
}
break;
case OPN_ACC:
rc = cmfld("Account for FTP server","",&p,xxstring);
if (rc == -3) {
makestr(&ftp_acc,NULL);
} else if (rc < 0) {
goto xopenftp;
} else {
makestr(&ftp_acc,brstrip(p));
}
break;
case OPN_ACT:
opn_psv = 0;
break;
case OPN_PSV:
opn_psv = 1;
break;
case OPN_TLS:
opn_tls = 1;
break;
default:
break;
}
}
if (n == 0) { /* After first time through */
cmfdbi(&sw, /* accept only switches */
_CMKEY,
"\nCarriage return to confirm to command, or switch",
"",
"",
nftpswi,
4,
xxstring,
ftpswitab,
&cm
);
}
}
#ifdef COMMENT
debug(F100,"ftp openftp while exit","",0);
rc = cmcfm();
debug(F101,"ftp openftp cmcfm rc","",rc);
if (rc < 0)
goto xopenftp;
#endif /* COMMENT */
if (opn_psv > -1) { /* /PASSIVE or /ACTIVE switch given */
sav_psv = ftp_psv;
ftp_psv = opn_psv;
}
if (nologin || haveuser) { /* /NOLOGIN or /USER switch given */
sav_log = ftp_log;
ftp_log = haveuser ? 1 : 0;
}
if (*hostname == '=') { /* Bypass directory lookup */
hostname++; /* if hostname starts with '=' */
havehost++;
} else if (isdigit(*hostname)) { /* or if it starts with a digit */
havehost++;
}
if (!service)
makestr(&service,opn_tls?"ftps":"ftp");
#ifndef NODIAL
if (!havehost && nnetdir > 0) { /* If there is a networks directory */
lunet(hostname); /* Look up the name */
debug(F111,"ftp openftp lunet",hostname,nhcount);
if (nhcount == 0) {
if (testing)
printf(" ftp open trying \"%s %s\"...\n",hostname,service);
success = ftpopen(hostname,service,opn_tls);
debug(F101,"ftp openftp A ftpopen success","",success);
rc = success;
} else {
int found = 0;
for (i = 0; i < nhcount; i++) {
if (nh_p2[i]) /* If network type specified */
if (ckstrcmp(nh_p2[i],"tcp/ip",strlen(nh_p2[i]),0))
continue;
found++;
makestr(&hostname,nh_p[i]);
debug(F111,"ftpopen lunet substitution",hostname,i);
if (testing)
printf(" ftp open trying \"%s %s\"...\n",hostname,service);
success = ftpopen(hostname,service,opn_tls);
debug(F101,"ftp openftp B ftpopen success","",success);
rc = success;
if (success)
break;
}
if (!found) { /* E.g. if no network types match */
if (testing)
printf(" ftp open trying \"%s %s\"...\n",hostname,service);
success = ftpopen(hostname,service,opn_tls);
debug(F101,"ftp openftp C ftpopen success","",success);
rc = success;
}
}
} else {
#endif /* NODIAL */
if (testing)
printf(" ftp open trying \"%s %s\"...\n",hostname,service);
success = ftpopen(hostname,service,opn_tls);
debug(F111,"ftp openftp D ftpopen success",hostname,success);
debug(F111,"ftp openftp D ftpopen connected",hostname,connected);
rc = success;
#ifndef NODIAL
}
#endif /* NODIAL */
xopenftp:
debug(F101,"ftp openftp xopenftp rc","",rc);
if (hostsave) free(hostsave);
if (service) free(service);
if (rc < 0 && ftp_logname) {
free(ftp_logname);
ftp_logname = NULL;
}
if (ftp_tmp) {
free(ftp_tmp);
ftp_tmp = NULL;
}
return(rc);
}
int
doftpacct() {
int x;
char * s;
if ((x = cmtxt("Remote account", "", &s, xxstring)) < 0)
return(x);
CHECKCONN();