| /* 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(); |
| |