3 /* C K C F T P -- FTP Client for C-Kermit */
5 char *ckftpv = "FTP Client, 9.0.259, 15 Jun 2011";
9 Jeffrey E Altman <jaltman@secure-endpoints.com>
10 Secure Endpoints Inc., New York City
11 Frank da Cruz <fdc@columbia.edu>,
12 The Kermit Project, Columbia University.
14 Copyright (C) 2000, 2011,
15 Trustees of Columbia University in the City of New York.
16 All rights reserved. See the C-Kermit COPYING.TXT file or the
17 copyright text in the ckcmai.c module for disclaimer and permissions.
19 Portions of conditionally included code Copyright Regents of the
20 University of California and The Stanford SRP Authentication Project;
27 . Implement recursive NLST downloads by trying to CD to each filename.
28 If it works, it's a directory; if not, it's a file -- GET it. But
29 that won't work with servers like wu-ftpd that don't send directory
30 names. Recursion with MLSD is done.
32 . Make syslog entries for session? Files?
34 . Messages are printed to stdout and stderr in random fashion. We should
35 either print everything to stdout, or else be systematic about when
38 . Implement mail (MAIL, MLFL, MSOM, etc) if any servers support it.
40 . Adapt to VMS. Big job because of its record-oriented file system.
41 RMS programmer required. There are probably also some VMS TCP/IP
42 product-specific wrinkles, e.g. attribute preservation in VMS-to-VMS
43 transfers using special options for Multinet or other FTP servers
44 (find out about STRU VMS).
48 Quick FTP command reference:
50 RFC765 (1980) and earlier:
51 MODE S(tream), B(lock), C(ompressed)
52 STRU F(ILE), R(ECORD), P(AGE)
53 TYPE A(SCII) <format>, E(BCDIC) <format>, I(MAGE), L(OCAL) <bytesize>
59 CWD - Change Working Directory
60 REIN - Logout but not disconnect
73 SITE - Site parameters or commands
79 CDUP - Change to Parent Directory
80 SMNT - Structure Mount
82 RMD - Remove Directory
88 FEAT - List Features (done)
89 OPTS - Send options (done)
92 LANG - Specify language for messages (not done)
94 Pending (Internet Drafts):
95 SIZE - File size (done)
96 MDTM - File modification date-time (done)
97 MLST - File name and attribute list (single file) (not done)
98 MLSD - File list with attributes (multiple files) (done)
99 MAIL, MLFL, MSOM - mail delivery (not done)
101 Alphabetical syntax list:
103 ACCT <SP> <account-information> <CRLF>
104 ALLO <SP> <decimal-integer> [<SP> R <SP> <decimal-integer>] <CRLF>
105 APPE <SP> <pathname> <CRLF>
107 CWD <SP> <pathname> <CRLF>
108 DELE <SP> <pathname> <CRLF>
110 HELP [<SP> <string>] <CRLF>
111 LANG [<SP> <language-tag> ] <CRLF>
112 LIST [<SP> <pathname>] <CRLF>
113 MKD <SP> <pathname> <CRLF>
114 MLSD [<SP> <pathname>] <CRLF>
115 MLST [<SP> <pathname>] <CRLF>
116 MODE <SP> <mode-code> <CRLF>
117 NLST [<SP> <pathname-or-wildcard>] <CRLF>
119 OPTS <SP> <commandname> [ <SP> <command-options> ] <CRLF>
120 PASS <SP> <password> <CRLF>
122 PORT <SP> <host-port> <CRLF>
126 REST <SP> <marker> <CRLF>
127 RETR <SP> <pathname> <CRLF>
128 RMD <SP> <pathname> <CRLF>
129 RNFR <SP> <pathname> <CRLF>
130 RNTO <SP> <pathname> <CRLF>
131 SITE <SP> <string> <CRLF>
132 SIZE <SP> <pathname> <CRLF>
133 SMNT <SP> <pathname> <CRLF>
134 STAT [<SP> <pathname>] <CRLF>
135 STOR <SP> <pathname> <CRLF>
137 STRU <SP> <structure-code> <CRLF>
139 TYPE <SP> <type-code> <CRLF>
140 USER <SP> <username> <CRLF>
142 #include "ckcsym.h" /* Standard includes */
145 #ifndef NOFTP /* NOFTP = no FTP */
146 #ifndef SYSFTP /* SYSFTP = use external ftp client */
147 #ifdef TCPSOCKET /* Build only if TCP/IP included */
150 /* Note: much of the following duplicates what was done in ckcdeb.h */
151 /* but let's not mess with it unless it causes trouble. */
157 #endif /* CK_ANSIC */
168 #include <setjmpex.h>
180 /* 2010-03-09 SMS. VAX C needs help to find "sys". It's easier not to try. */
183 #include <sys/stat.h>
184 #endif /* def VMS [else] */
191 #define EPIPE 32 /* Broken pipe error */
194 /* Kermit includes */
200 #include "ckcnet.h" /* Includes ckctel.h */
201 #include "ckctel.h" /* (then why include it again?) */
205 #include "ckuath.h" /* SMS 2007/02/15 */
206 #endif /* def CK_SSL */
209 How to get the struct timeval definition so we can call select(). The
210 xxTIMEH symbols are defined in ckcdeb.h, overridden in various makefile
211 targets. The problem is: maybe we have already included some header file
212 that defined struct timeval, and maybe we didn't. If we did, we don't want
213 to include another header file that defines it again or the compilation will
214 fail. If we didn't, we have to include the header file where it's defined.
215 But in some cases even that won't work because of strict POSIX constraints
216 or somesuch, or because this introduces other conflicts (e.g. struct tm
217 multiply defined), in which case we have to define it ourselves, but this
218 can work only if we didn't already encounter a definition.
227 #endif /* SV68R3V6 */
228 #endif /* DCLTIMEVAL */
231 /* Also maybe in some places the elements must be unsigned... */
237 /* Currently we don't use this... */
243 #else /* !DCLTIMEVAL */
246 #include <sys/time.h>
247 #endif /* SYSTIMEH */
248 #endif /* NOSYSTIMEH */
251 #include <sys/timeb.h>
252 #endif /* SYSTIMEBH */
253 #endif /* NOSYSTIMEBH */
254 #endif /* DCLTIMEVAL */
256 /* 2010-03-09 SMS. VAX C needs help to find "sys". It's easier not to try. */
260 #include <sys/types.h>
261 #endif /* def VMS [else] */
266 #endif /* HAVE_STDLIB_H */
270 /* This section moved to ckcdeb.h */
284 #ifdef VMS /* SMS 2007/02/15 */
285 #include "ckvrtl.h" /* for utime() */
288 #include <sys/utime.h>
294 #endif /* SYSUTIMEH */
296 #endif /* NOSETTIME */
300 #include <sys/select.h>
301 #endif /* SELECT_H */
302 #endif /* SCO_OSR504 */
304 #ifndef INADDR_NONE /* 2010-03-29 */
305 #define INADDR_NONE -1
306 #endif /* INADDR_NONE */
308 /* select() dialects... */
311 #define BSDSELECT /* BSD select() syntax/semantics */
313 #define FD_SETSIZE 128
314 #endif /* FD_SETSIZE */
315 #ifdef HPUX6 /* For HP-UX 6.5 circa 1989 */
316 typedef long fd_mask;
317 #define NFDBITS (sizeof(fd_mask) * NBBY) /* bits per mask */
319 #define howmany(x, y) (((x)+((y)-1))/(y))
321 #define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
322 #define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
323 #define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
324 #define FD_COPY(f, t) bcopy(f, t, sizeof(*(f)))
325 #define FD_ZERO(p) bzero(p, sizeof(*(p)))
329 #ifdef OS2 /* OS/2 or Win32 */
339 #define BSDSELECT /* SMS 2007/02/15 */
342 /* Other select() peculiarities */
345 #ifndef HPUX10 /* HP-UX 9.xx and earlier */
347 /* The three interior args to select() are (int *) rather than (fd_set *) */
350 #endif /* INTSELECT */
351 #endif /* HPUX1100 */
355 #ifdef CK_SOCKS /* SOCKS Internet relay package */
356 #ifdef CK_SOCKS5 /* SOCKS 5 */
357 #define accept SOCKSaccept
358 #define bind SOCKSbind
359 #define connect SOCKSconnect
360 #define getsockname SOCKSgetsockname
361 #define listen SOCKSlisten
362 #else /* Not SOCKS 5 */
363 #define accept Raccept
365 #define connect Rconnect
366 #define getsockname Rgetsockname
367 #define listen Rlisten
368 #endif /* CK_SOCKS5 */
369 #endif /* CK_SOCKS */
372 extern char * tcp_http_proxy; /* Name[:port] of http proxy server */
373 extern int tcp_http_proxy_errno;
374 extern char * tcp_http_proxy_user;
375 extern char * tcp_http_proxy_pwd;
376 extern char * tcp_http_proxy_agent;
377 #define HTTPCPYL 1024
378 static char proxyhost[HTTPCPYL];
380 int ssl_ftp_proxy = 0; /* FTP over SSL/TLS Proxy Server */
382 /* Feature selection */
386 We don't use shutdown() because (a) we always call it just before close()
387 so it's redundant and unnecessary, and (b) it introduces a long pause on
388 some platforms like SV/68 R3.
390 /* #define USE_SHUTDOWN */
391 #endif /* USE_SHUTDOWN */
394 #ifndef NORESTART /* Restart / recover */
397 #endif /* FTP_RESTART */
398 #endif /* NORESTART */
399 #endif /* NORESEND */
401 #ifndef NOUPDATE /* Update mode */
404 #endif /* DOUPDATE */
405 #endif /* NOUPDATE */
407 #ifndef UNICODE /* Unicode required */
408 #ifndef NOCSETS /* for charset translation */
414 #ifndef HAVE_MSECS /* Millisecond timer */
420 #endif /* HAVE_MSECS */
423 #ifdef PIPESEND /* PUT from pipe */
427 #endif /* PIPESEND */
429 #ifndef NOSPL /* PUT from array */
432 #endif /* PUTARRAY */
444 There is a conflict between the Key Schedule formats used internally
445 within the standalone MIT KRB4 library and that used by Eric Young
446 in OpenSSL and his standalone DES library. Therefore, KRB4 FTP AUTH
447 cannot be supported when either of those two packages are used.
461 #ifndef NOFTP_GSSAPI /* 299 */
463 #endif /* NOFTP_GSSAPI */
466 #endif /* CK_KERBEROS */
468 /* FTP_SECURITY is defined if any of the above is selected */
483 #endif /* FTP_KRB4 */
484 #endif /* FTP_GSSAPI */
485 #endif /* FTP_SECURITY */
499 #endif /* CRYPT_DLL */
502 #define des_cblock Block
503 #define des_key_schedule Schedule
508 #include "kerberosIV/krb.h"
512 /* For some reason lost in history the Makefile Solaris targets have -Usun */
517 #define krb_get_err_text_entry krb_get_err_text
519 #endif /* FTP_KRB4 */
525 #endif /* HEADER_DES_H */
526 #endif /* FTP_KRB4 */
533 #endif /* HAVE_PWD_H */
535 #include "t_client.h"
540 #include <gssapi/gssapi.h>
542 Need to include the krb5 file, because we're doing manual fallback
543 from the v2 mech to the v1 mech. Once there's real negotiation,
544 we can be generic again.
546 #include <gssapi/gssapi_generic.h>
547 #include <gssapi/gssapi_krb5.h>
548 static gss_ctx_id_t gcontext;
551 /** exported constants defined in gssapi_krb5{,_nx}.h **/
553 /* these are bogus, but will compile */
556 * The OID of the draft krb5 mechanism, assigned by IETF, is:
557 * iso(1) org(3) dod(5) internet(1) security(5)
558 * kerberosv5(2) = 1.3.5.1.5.2
559 * The OID of the krb5_name type is:
560 * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
561 * krb5(2) krb5_name(1) = 1.2.840.113554.1.2.2.1
562 * The OID of the krb5_principal type is:
563 * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
564 * krb5(2) krb5_principal(2) = 1.2.840.113554.1.2.2.2
565 * The OID of the proposed standard krb5 mechanism is:
566 * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
567 * krb5(2) = 1.2.840.113554.1.2.2
568 * The OID of the proposed standard krb5 v2 mechanism is:
569 * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
570 * krb5v2(3) = 1.2.840.113554.1.2.3
575 * Encoding rules: The first two values are encoded in one byte as 40
576 * * value1 + value2. Subsequent values are encoded base 128, most
577 * significant digit first, with the high bit (\200) set on all octets
578 * except the last in each value's encoding.
581 static CONST gss_OID_desc
582 ck_krb5_gss_oid_array[] = {
583 /* this is the official, rfc-specified OID */
584 {9, "\052\206\110\206\367\022\001\002\002"},
585 /* this is the unofficial, wrong OID */
586 {5, "\053\005\001\005\002"},
587 /* this is the v2 assigned OID */
588 {9, "\052\206\110\206\367\022\001\002\003"},
589 /* these two are name type OID's */
590 {10, "\052\206\110\206\367\022\001\002\002\001"},
591 {10, "\052\206\110\206\367\022\001\002\002\002"},
596 CONST gss_OID_desc * CONST gss_mech_krb5_v2 = ck_krb5_gss_oid_array+2;
600 CONST gss_OID_desc * CONST gss_mech_krb5 = ck_krb5_gss_oid_array+0;
601 #endif /* MACOSX103 */
605 CONST gss_OID_desc * CONST gss_mech_krb5 = ck_krb5_gss_oid_array+0;
607 CONST gss_OID_desc * CONST gss_mech_krb5_old = ck_krb5_gss_oid_array+1;
609 CONST gss_OID_desc * CONST gss_nt_krb5_name = ck_krb5_gss_oid_array+3;
611 CONST gss_OID_desc * CONST gss_nt_krb5_principal = ck_krb5_gss_oid_array+4;
615 * See krb5/gssapi_krb5.c for a description of the algorithm for
616 * encoding an object identifier.
620 * The OID of user_name is:
621 * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
622 * generic(1) user_name(1) = 1.2.840.113554.1.2.1.1
624 * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
625 * generic(1) machine_uid_name(2) = 1.2.840.113554.1.2.1.2
627 * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
628 * generic(1) string_uid_name(3) = 1.2.840.113554.1.2.1.3
630 * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
631 * generic(1) service_name(4) = 1.2.840.113554.1.2.1.4
633 * 1(iso), 3(org), 6(dod), 1(internet), 5(security), 6(nametypes),
634 * 4(gss-api-exported-name)
635 * host_based_service_name (v2):
636 * iso (1) org (3), dod (6), internet (1), security (5), nametypes(6),
637 * gss-host-based-services(2)
640 static gss_OID_desc ck_oids[] = {
641 {10, "\052\206\110\206\367\022\001\002\001\001"},
642 {10, "\052\206\110\206\367\022\001\002\001\002"},
643 {10, "\052\206\110\206\367\022\001\002\001\003"},
644 {10, "\052\206\110\206\367\022\001\002\001\004"},
645 { 6, "\053\006\001\005\006\004"},
646 { 6, "\053\006\001\005\006\002"},
649 static gss_OID ck_gss_nt_user_name = ck_oids+0;
650 static gss_OID ck_gss_nt_machine_uid_name = ck_oids+1;
651 static gss_OID ck_gss_nt_string_uid_name = ck_oids+2;
652 static gss_OID ck_gss_nt_service_name = ck_oids+3;
653 static gss_OID ck_gss_nt_exported_name = ck_oids+4;
654 static gss_OID ck_gss_nt_service_name_v2 = ck_oids+5;
656 #endif /* FTP_GSSAPI */
669 #endif /* CK_ENCRYPTION */
670 #endif /* FTP_KRB4 */
674 #endif /* FTP_GSSAPI */
677 extern int k95stdout, wherex[], wherey[];
678 extern unsigned char colorcmd;
682 static char ftp_realm[REALM_SZ + 1];
683 static KTEXT_ST ftp_tkt;
685 static LEASH_CREDENTIALS ftp_cred;
687 static CREDENTIALS ftp_cred;
689 static MSG_DAT ftp_msg_data;
690 static des_key_schedule ftp_sched;
691 static int foo[4] = {99,99,99,99};
692 #endif /* FTP_KRB4 */
694 /* getreply() function codes */
696 #define GRF_AUTH 1 /* Reply to AUTH command */
697 #define GRF_FEAT 2 /* Reply to FEAT command */
699 /* Operational definitions */
701 #define DEF_VBM 0 /* Default verbose mode */
702 /* #define SETVBM */ /* (see getreply) */
704 #define URL_ONEFILE /* GET, not MGET, for FTP URL */
706 #define FTP_BUFSIZ 10240 /* Max size for FTP cmds & replies */
707 #define SRVNAMLEN 32 /* Max length for server type name */
709 #define PASSBUFSIZ 256
710 #define PROMPTSIZ 256
712 #ifndef MGETMAX /* Max operands for MGET command */
717 #define FUDGE_FACTOR 100
721 Amount of growth from cleartext to ciphertext. krb_mk_priv adds this
722 number bytes. Must be defined for each auth type.
723 GSSAPI appears to add 52 bytes, but I'm not sure it is a constant--hartmans
724 3DES requires 56 bytes. Lets use 96 just to be sure.
728 #define FUDGE_FACTOR 96
729 #endif /* FUDGE_FACTOR */
730 #endif /* FTP_GSSAPI */
734 #define FUDGE_FACTOR 32
735 #endif /* FUDGE_FACTOR */
736 #endif /* FTP_KRB4 */
738 #ifndef FUDGE_FACTOR /* In case no auth types define it */
739 #define FUDGE_FACTOR 0
740 #endif /* FUDGE_FACTOR */
742 #ifndef MAXHOSTNAMELEN
743 #define MAXHOSTNAMELEN 64
744 #endif /* MAXHOSTNAMELEN */
745 #define MAX_DNS_NAMELEN (15*(MAXHOSTNAMELEN + 1)+1)
747 /* Fascist compiler toadying */
750 #ifdef COMMENT /* Might be needed here and there */
751 #define SENDARG2TYPE const char *
753 #define SENDARG2TYPE char *
755 #endif /* SENDARG2TYPE */
757 /* Common text messages */
759 static char *nocx = "?No FTP control connection\n";
761 static char *fncnam[] = {
762 "rename", "overwrite", "backup", "append", "discard", "ask", "update",
766 /* Macro definitions */
768 /* Used to speed up text-mode PUTs */
769 #define zzout(fd,c) \
770 ((fd<0)?(-1):((nout>=ucbufsiz)?(zzsend(fd,c)):(ucbuf[nout++]=c)))
772 #define CHECKCONN() if(!connected){printf(nocx);return(-9);}
777 extern struct urldata g_url;
781 extern char *zinbuffer, *zoutbuffer; /* Regular Kermit file i/o */
783 extern char zinbuffer[], zoutbuffer[];
785 extern char *zinptr, *zoutptr;
786 extern int zincnt, zoutcnt, zobufsize, fncact;
789 extern int f_tmpdir; /* Directory changed temporarily */
790 extern char savdir[]; /* For saving current directory */
792 #endif /* CK_TMPDIR */
794 extern char * rfspec, * sfspec, * srfspec, * rrfspec; /* For WHERE command */
796 extern xx_strp xxstring;
797 extern struct keytab onoff[], txtbin[], rpathtab[];
798 extern int nrpathtab, xfiletype, patterns, gnferror, moving, what, pktnum;
799 extern int success, nfils, sndsrc, quiet, nopush, recursive, inserver, binary;
800 extern int filepeek, nscanfile, fsecs, xferstat, xfermode, lastxfer, tsecs;
801 extern int backgrd, spackets, rpackets, spktl, rpktl, xaskmore, cmd_rows;
802 extern int nolinks, msgflg, keep;
803 extern CK_OFF_T fsize, ffc, tfc, sendstart, sndsmaller, sndlarger, rs_len;
804 extern long filcnt, xfsecs, tfcps, cps, oldcps;
807 int ftp_timed_out = 0;
808 long ftp_timeout = 0;
809 #endif /* FTP_TIMEOUT */
812 extern CKFLOAT fptsecs, fpfsecs, fpxfsecs;
817 extern char filnam[], * filefile, myhost[];
818 extern char * snd_move, * rcv_move, * snd_rename, * rcv_rename;
819 extern int g_skipbup, skipbup, sendmode;
820 extern int g_displa, fdispla, displa;
823 extern int locus, autolocus;
827 extern int nfilc, dcset7, dcset8, fileorder;
828 extern struct csinfo fcsinfo[];
829 extern struct keytab fcstab[];
833 extern char sndbefore[], sndafter[], *sndexcept[]; /* Selection criteria */
834 extern char sndnbefore[], sndnafter[], *rcvexcept[];
837 extern char * remdest;
838 extern int remfile, remappd, rempipe;
841 extern int cmd_quoting;
843 extern int sndxlo, sndxhi, sndxin;
844 extern char sndxnam[];
845 extern char **a_ptr[]; /* Array pointers */
846 extern int a_dim[]; /* Array dimensions */
847 #endif /* PUTARRAY */
850 #ifndef NOMSEND /* MPUT and ADD SEND-LIST lists */
851 extern char *msfiles[];
852 extern int filesinlist;
853 extern struct filelist * filehead;
854 extern struct filelist * filetail;
855 extern struct filelist * filenext;
857 extern char fspec[]; /* Most recent filespec */
858 extern int fspeclen; /* Length of fspec[] buffer */
863 extern char * sndfilter, * rcvfilter;
864 #endif /* PIPESEND */
867 extern int ckrooterr;
871 extern int krb4_autoget;
872 _PROTOTYP(char * ck_krb4_realmofhost,(char *));
876 extern int krb5_autoget;
877 extern int krb5_d_no_addresses;
878 _PROTOTYP(char * ck_krb5_realmofhost,(char *));
882 extern char *atmbuf; /* Atom buffer (malloc'd) */
883 extern char *cmdbuf; /* Command buffer (malloc'd) */
884 extern char *line; /* Big string buffer #1 */
885 extern char *tmpbuf; /* Big string buffer #2 */
887 extern char atmbuf[]; /* The same, but static */
888 extern char cmdbuf[];
890 extern char tmpbuf[];
893 extern char * cmarg, * cmarg2, ** cmlist; /* For setting up file lists */
895 /* Public variables declared here */
898 int ftpget = 1; /* GET/PUT/REMOTE orientation FTP */
900 int ftpget = 2; /* GET/PUT/REMOTE orientation AUTO */
902 int ftpcode = -1; /* Last FTP response code */
903 int ftp_cmdlin = 0; /* FTP invoked from command line */
904 int ftp_fai = 0; /* FTP failure count */
905 int ftp_deb = 0; /* FTP debugging */
906 int ftp_dis = -1; /* FTP display style */
907 int ftp_log = 1; /* FTP Auto-login */
909 int ftp_action = 0; /* FTP action from command line */
910 int ftp_dates = 1; /* Set file dates from server */
911 int ftp_xfermode = XMODE_A; /* FTP-specific transfer mode */
913 char ftp_reply_str[FTP_BUFSIZ] = ""; /* Last line of previous reply */
914 char ftp_srvtyp[SRVNAMLEN] = { NUL, NUL }; /* Server's system type */
915 char ftp_user_host[MAX_DNS_NAMELEN]= ""; /* FTP hostname specified by user */
916 char * ftp_host = NULL; /* FTP hostname */
917 char * ftp_logname = NULL; /* FTP username */
918 char * ftp_rdir = NULL; /* Remote directory from cmdline */
919 char * ftp_apw = NULL; /* Anonymous password */
921 /* Definitions and typedefs needed for prototypes */
923 #define sig_t my_sig_t
924 #define sigtype SIGTYP
925 typedef sigtype (*sig_t)();
927 /* Static global variables */
929 static char ftpsndbuf[FTP_BUFSIZ+64];
931 static char * fts_sto = NULL;
933 static int ftpsndret = 0;
934 static struct _ftpsnd {
935 sig_t oldintr, oldintp;
939 char * cmd, * local, * remote;
947 This is just a first stab -- these strings should match how the
948 corresponding FTP servers identify themselves.
951 static char * myostype = "UNIX";
955 static char * myostype = "VMS";
959 static char * myostype = "WIN32";
961 static char * myostype = "OS/2";
964 static char * myostype = "UNSUPPORTED";
969 static int noinit = 0; /* Don't send REST, STRU, MODE */
970 static int alike = 0; /* Client/server like platforms */
971 static int local = 1; /* Shadows Kermit global 'local' */
972 static int dout = -1; /* Data connection file descriptor */
973 static int dpyactive = 0; /* Data transfer is active */
974 static int globaldin = -1; /* Data connection f.d. */
975 static int out2screen = 0; /* GET output is to screen */
976 static int forcetype = 0; /* Force text or binary mode */
977 static int cancelfile = 0; /* File canceled */
978 static int cancelgroup = 0; /* Group canceled */
979 static int anonymous = 0; /* Logging in as anonymous */
980 static int loggedin = 0; /* Logged in (or not) */
981 static int puterror = 0; /* What to do on PUT error */
982 static int geterror = 0; /* What to do on GET error */
983 static int rfrc = 0; /* remote_files() return code */
984 static int okrestart = 0; /* Server understands REST */
985 static int printlines = 0; /* getreply()should print data lines */
986 static int haveurl = 0; /* Invoked by command-line FTP URL */
987 static int mdtmok = 1; /* Server supports MDTM */
988 static int sizeok = 1;
989 static int featok = 1;
990 static int mlstok = 1;
991 static int stouarg = 1;
992 static int typesent = 0;
993 static int havesigint = 0;
994 static long havetype = 0;
995 static CK_OFF_T havesize = (CK_OFF_T)-1;
996 static char * havemdtm = NULL;
997 static int mgetmethod = 0; /* NLST or MLSD */
998 static int mgetforced = 0;
1000 static int i, /* j, k, */ x, y, z; /* Volatile temporaries */
1001 static int c0, c1; /* Temp variables for characters */
1003 static char putpath[CKMAXPATH+1] = { NUL, NUL };
1004 static char asnambuf[CKMAXPATH+1] = { NUL, NUL };
1006 #define RFNBUFSIZ 4096 /* Remote filename buffer size */
1008 static unsigned int maxbuf = 0, actualbuf = 0;
1009 static CHAR *ucbuf = NULL;
1010 static int ucbufsiz = 0;
1011 static unsigned int nout = 0; /* Number of chars in ucbuf */
1013 static jmp_buf recvcancel;
1014 static jmp_buf sendcancel;
1015 static jmp_buf ptcancel;
1016 static jmp_buf jcancel;
1017 static int ptabflg = 0;
1019 /* Protection level symbols */
1021 #define FPL_CLR 1 /* Clear */
1022 #define FPL_SAF 2 /* Safe */
1023 #define FPL_PRV 3 /* Private */
1024 #define FPL_CON 4 /* Confidential */
1026 /* Symbols for file types returned by MLST/MLSD */
1028 #define FTYP_FILE 1 /* Regular file */
1029 #define FTYP_DIR 2 /* Directory */
1030 #define FTYP_CDIR 3 /* Current directory */
1031 #define FTYP_PDIR 4 /* Parent directory */
1033 /* File type symbols keyed to the file-type symbols from ckcker.h */
1035 #define FTT_ASC XYFT_T /* ASCII (text) */
1036 #define FTT_BIN XYFT_B /* Binary (image) */
1037 #define FTT_TEN XYFT_X /* TENEX (TOPS-20) */
1039 /* Server feature table - sfttab[0] > 0 means server supports FEAT and OPTS */
1041 static int sfttab[16] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
1043 #define SFT_AUTH 1 /* FTP server feature codes */
1054 #define CNV_AUTO 2 /* FTP filename conversion */
1058 /* SET FTP values */
1060 static int /* SET FTP values... */
1061 ftp_aut = 1, /* Auto-authentication */
1063 ftp_cry = 1, /* Auto-encryption */
1064 ftp_cfw = 0, /* Credential forwarding */
1065 #endif /* FTP_SECURITY */
1066 ftp_cpl = FPL_CLR, /* Command protection level */
1067 ftp_dpl = FPL_CLR, /* Data protection level */
1069 ftp_prx = 0, /* Use proxy */
1070 #endif /* FTP_PROXY */
1071 sav_psv = -1, /* For saving passive mode */
1072 ftp_psv = 1, /* Passive mode */
1073 ftp_spc = 1, /* Send port commands */
1074 ftp_typ = FTT_ASC, /* Type */
1075 get_auto = 1, /* Automatic type switching for GET */
1076 tenex = 0, /* Type is Tenex */
1077 ftp_usn = 0, /* Unique server names */
1078 ftp_prm = 0, /* Permissions */
1079 ftp_cnv = CNV_AUTO, /* Filename conversion (2 = auto) */
1080 ftp_vbm = DEF_VBM, /* Verbose mode */
1081 ftp_vbx = DEF_VBM, /* Sticky version of same */
1082 ftp_err = 0, /* Error action */
1083 ftp_fnc = -1; /* Filename collision action */
1086 static int ftp_bug_use_ssl_v2 = 0; /* use SSLv2 for AUTH SSL */
1091 ftp_csr = -1, /* Remote (server) character set */
1094 #endif /* NOCSETS */
1095 ftp_xla = 0; /* Character-set translation on/off */
1097 ftp_csx = -1, /* Remote charset currently in use */
1098 ftp_csl = -1; /* Local charset currently in use */
1100 static int g_ftp_typ = FTT_ASC; /* For saving and restoring ftp_typ */
1102 char * ftp_nml = NULL; /* /NAMELIST */
1103 char * ftp_tmp = NULL; /* Temporary string */
1104 static char * ftp_acc = NULL; /* Account string */
1105 static char * auth_type = NULL; /* Authentication type */
1106 static char * srv_renam = NULL; /* Server-rename string */
1107 FILE * fp_nml = NULL; /* Namelist file pointer */
1109 static int csocket = -1; /* Control socket */
1110 static int connected = 0; /* Connected to FTP server */
1111 /* static unsigned short ftp_port = 0; */ /* FTP port */
1112 /* static int ftp_port = 0; */ /* SMS 2007/02/15 */
1113 static int ftp_port = 0; /* fdc 2007/08/30 */
1115 static int hostcmd = 0; /* Has HOST command been sent */
1116 #endif /* FTPHOST */
1117 static int form, mode, stru, bytesize, curtype = FTT_ASC;
1118 static char bytename[8];
1120 /* For parsing replies to FTP server command */
1121 static char *reply_parse, reply_buf[FTP_BUFSIZ], *reply_ptr;
1124 static int proxy, unix_proxy
1125 #endif /* FTP_PROXY */
1127 static char pasv[64]; /* Passive-mode port */
1128 static int passivemode = 0;
1129 static int sendport = 0;
1130 static int servertype = 0; /* FTP server's OS type */
1132 static int testing = 0;
1133 static char ftpcmdbuf[FTP_BUFSIZ];
1135 /* Macro definitions */
1137 #define UC(b) ckitoa(((int)b)&0xff)
1138 #define nz(x) ((x) == 0 ? 1 : (x))
1140 /* Command tables and definitions */
1142 #define FTP_ACC 1 /* FTP command keyword codes */
1182 struct keytab gprtab[] = { /* GET-PUT-REMOTE keywords */
1188 static struct keytab qorp[] = { /* QUIT or PROCEED keywords */
1189 { "proceed", 0, 0 }, /* 0 = proceed */
1190 { "quit", 1, 0 } /* 1 = quit */
1193 static struct keytab ftpcmdtab[] = { /* FTP command table */
1194 { "account", FTP_ACC, 0 },
1195 { "append", FTP_APP, 0 },
1196 { "bye", FTP_CLS, 0 },
1197 { "cd", FTP_CWD, 0 },
1198 { "cdup", FTP_GUP, 0 },
1199 { "check", FTP_CHK, 0 },
1200 { "chmod", FTP_CHM, 0 },
1201 { "close", FTP_CLS, 0 },
1202 { "cwd", FTP_CWD, CM_INV },
1203 { "delete", FTP_MDE, 0 },
1204 { "directory", FTP_DIR, 0 },
1205 { "disable", FTP_DIS, 0 },
1206 { "enable", FTP_ENA, 0 },
1207 { "features", FTP_FEA, 0 },
1208 { "get", FTP_GET, 0 },
1209 { "help", FTP_HLP, 0 },
1210 { "idle", FTP_IDL, 0 },
1211 { "login", FTP_USR, CM_INV },
1212 { "mdelete", FTP_MDE, CM_INV },
1213 { "mget", FTP_MGE, 0 },
1214 { "mkdir", FTP_MKD, 0 },
1215 { "modtime", FTP_MOD, 0 },
1216 { "mput", FTP_MPU, 0 },
1217 { "open", FTP_OPN, 0 },
1218 { "opt", FTP_OPT, CM_INV|CM_ABR },
1219 { "opts", FTP_OPT, CM_INV },
1220 { "options", FTP_OPT, 0 },
1221 { "put", FTP_PUT, 0 },
1222 { "pwd", FTP_PWD, 0 },
1223 { "quit", FTP_CLS, CM_INV },
1224 { "quote", FTP_QUO, 0 },
1225 { "reget", FTP_RGE, 0 },
1226 { "rename", FTP_REN, 0 },
1227 { "reput", FTP_REP, 0 },
1228 { "resend", FTP_REP, CM_INV },
1229 { "reset", FTP_RES, 0 },
1230 { "rmdir", FTP_RMD, 0 },
1231 { "send", FTP_PUT, CM_INV },
1232 { "site", FTP_SIT, 0 },
1233 { "size", FTP_SIZ, 0 },
1234 { "status", FTP_STA, 0 },
1235 { "system", FTP_SYS, 0 },
1236 { "type", FTP_TYP, 0 },
1237 { "umask", FTP_UMA, 0 },
1238 { "up", FTP_GUP, CM_INV },
1239 { "user", FTP_USR, 0 },
1240 { "vdirectory",FTP_VDI, 0 },
1243 static int nftpcmd = (sizeof(ftpcmdtab) / sizeof(struct keytab)) - 1;
1245 #define OPN_ANO 1 /* FTP OPEN switch codes */
1258 static struct keytab tlstab[] = { /* FTP SSL/TLS switches */
1259 { "/ssl", OPN_TLS, 0 },
1260 { "/tls", OPN_TLS, 0 },
1263 static int ntlstab = (sizeof(tlstab) / sizeof(struct keytab)) - 1;
1265 #endif /* FTP_SECURITY */
1267 static struct keytab ftpswitab[] = { /* FTP command switches */
1268 { "/account", OPN_ACC, CM_ARG },
1269 { "/active", OPN_ACT, 0 },
1270 { "/anonymous", OPN_ANO, 0 },
1271 { "/noinit", OPN_NIN, 0 },
1272 { "/nologin", OPN_NOL, 0 },
1273 { "/passive", OPN_PSV, 0 },
1274 { "/password", OPN_PSW, CM_ARG },
1275 { "/user", OPN_USR, CM_ARG },
1278 static int nftpswi = (sizeof(ftpswitab) / sizeof(struct keytab)) - 1;
1280 /* FTP { ENABLE, DISABLE } items */
1288 static struct keytab ftpenatab[] = {
1289 { "AUTH", ENA_AUTH, 0 },
1290 { "FEAT", ENA_FEAT, 0 },
1291 { "MDTM", ENA_MDTM, 0 },
1292 { "ML", ENA_MLST, CM_INV|CM_ABR },
1293 { "MLS", ENA_MLST, CM_INV|CM_ABR },
1294 { "MLSD", ENA_MLST, CM_INV },
1295 { "MLST", ENA_MLST, 0 },
1296 { "SIZE", ENA_SIZE, 0 },
1299 static int nftpena = (sizeof(ftpenatab) / sizeof(struct keytab)) - 1;
1301 /* SET FTP command keyword indices */
1303 #define FTS_AUT 1 /* Autoauthentication */
1304 #define FTS_CRY 2 /* Encryption */
1305 #define FTS_LOG 3 /* Autologin */
1306 #define FTS_CPL 4 /* Command protection level */
1307 #define FTS_CFW 5 /* Credentials forwarding */
1308 #define FTS_DPL 6 /* Data protection level */
1309 #define FTS_DBG 7 /* Debugging */
1310 #define FTS_PSV 8 /* Passive mode */
1311 #define FTS_SPC 9 /* Send port commands */
1312 #define FTS_TYP 10 /* (file) Type */
1313 #define FTS_USN 11 /* Unique server names (for files) */
1314 #define FTS_VBM 12 /* Verbose mode */
1315 #define FTS_ATP 13 /* Authentication type */
1316 #define FTS_CNV 14 /* Filename conversion */
1317 #define FTS_TST 15 /* Test (progress) messages */
1318 #define FTS_PRM 16 /* (file) Permissions */
1319 #define FTS_XLA 17 /* Charset translation */
1320 #define FTS_CSR 18 /* Server charset */
1321 #define FTS_ERR 19 /* Error action */
1322 #define FTS_FNC 20 /* Collision */
1323 #define FTS_SRP 21 /* SRP options */
1324 #define FTS_GFT 22 /* GET automatic file-type switching */
1325 #define FTS_DAT 23 /* Set file dates */
1326 #define FTS_STO 24 /* Server time offset */
1327 #define FTS_APW 25 /* Anonymous password */
1328 #define FTS_DIS 26 /* File-transfer display style */
1329 #define FTS_BUG 27 /* Bug(s) */
1330 #define FTS_TMO 28 /* Timeout */
1334 #define FTB_SV2 1 /* use SSLv2 */
1336 static struct keytab ftpbugtab[] = {
1337 { "use-ssl-v2", FTB_SV2, 0 }
1339 static int nftpbug = (sizeof(ftpbugtab) / sizeof(struct keytab));
1341 /* FTP PUT options (mutually exclusive, not a bitmask) */
1343 #define PUT_UPD 1 /* Update */
1344 #define PUT_RES 2 /* Restart */
1345 #define PUT_SIM 4 /* Simulation */
1346 #define PUT_DIF 8 /* Dates Differ */
1348 static struct keytab ftpcolxtab[] = { /* SET FTP COLLISION options */
1350 { "append", XYFX_A, 0 }, /* append to old file */
1353 { "ask", XYFX_Q, 0 }, /* ask what to do (not implemented) */
1355 { "backup", XYFX_B, 0 }, /* rename old file */
1357 { "dates-differ", XYFX_M, 0 }, /* accept if dates differ */
1358 { "discard", XYFX_D, 0 }, /* don't accept new file */
1359 { "no-supersede", XYFX_D, CM_INV }, /* ditto (MSK compatibility) */
1361 { "overwrite", XYFX_X, 0 }, /* overwrite the old file */
1362 { "rename", XYFX_R, 0 }, /* rename the incoming file */
1363 #ifndef MAC /* This crashes Mac Kermit. */
1364 { "update", XYFX_U, 0 }, /* replace if newer */
1368 static int nftpcolx = (sizeof(ftpcolxtab) / sizeof(struct keytab)) - 1;
1372 /* FTP authentication options */
1374 #define FTA_AUTO 0 /* Auto */
1375 #define FTA_SRP 1 /* SRP */
1376 #define FTA_GK5 2 /* Kerberos 5 */
1377 #define FTA_K4 3 /* Kerberos 4 */
1378 #define FTA_SSL 4 /* SSL */
1379 #define FTA_TLS 5 /* TLS */
1381 /* FTP authentication types */
1384 static int ftp_auth_type[FTPATYPS] = {
1386 FTA_GK5, /* GSSAPI Kerberos 5 */
1387 #endif /* FTP_GK5 */
1390 #endif /* FTP_SRP */
1392 FTA_K4, /* Kerberos 4 */
1393 #endif /* FTP_KRB4 */
1401 static struct keytab ftpauth[] = { /* SET FTP AUTHTYPE cmd table */
1402 { "automatic", FTA_AUTO, CM_INV },
1404 { "gssapi-krb5", FTA_GK5, 0 },
1405 #endif /* FTP_GSSAPI */
1407 { "k4", FTA_K4, CM_INV },
1408 #endif /* FTP_KRB4 */
1410 { "k5", FTA_GK5, CM_INV },
1411 #endif /* FTP_GSSAPI */
1413 { "kerberos4", FTA_K4, 0 },
1414 #endif /* FTP_KRB4 */
1416 { "kerberos5", FTA_GK5, CM_INV },
1417 #endif /* FTP_GSSAPI */
1419 { "kerberos_iv",FTA_K4, CM_INV },
1420 #endif /* FTP_KRB4 */
1422 { "kerberos_v", FTA_GK5, CM_INV },
1423 #endif /* FTP_GSSAPI */
1425 { "krb4", FTA_K4, CM_INV },
1426 #endif /* FTP_KRB4 */
1428 { "krb5", FTA_GK5, CM_INV },
1429 #endif /* FTP_GSSAPI */
1431 { "srp", FTA_SRP, 0 },
1432 #endif /* FTP_SRP */
1434 { "ssl", FTA_SSL, 0 },
1435 { "tls", FTA_TLS, 0 },
1439 static int nftpauth = (sizeof(ftpauth) / sizeof(struct keytab)) - 1;
1442 #define SRP_CIPHER 1
1444 static struct keytab ftpsrp[] = { /* SET FTP SRP command table */
1445 { "cipher", SRP_CIPHER, 0 },
1446 { "hash", SRP_HASH, 0 },
1449 static int nftpsrp = (sizeof(ftpsrp) / sizeof(struct keytab)) - 1;
1450 #endif /* FTP_SRP */
1451 #endif /* FTP_SECURITY */
1453 static struct keytab ftpset[] = { /* SET FTP commmand table */
1454 { "anonymous-password", FTS_APW, 0 },
1456 { "authtype", FTS_ATP, 0 },
1457 { "autoauthentication", FTS_AUT, 0 },
1458 { "autoencryption", FTS_CRY, 0 },
1459 #endif /* FTP_SECURITY */
1460 { "autologin", FTS_LOG, 0 },
1461 { "bug", FTS_BUG, 0 },
1463 { "character-set-translation",FTS_XLA, 0 },
1464 #endif /* NOCSETS */
1465 { "collision", FTS_FNC, 0 },
1467 { "command-protection-level", FTS_CPL, 0 },
1468 { "cpl", FTS_CPL, CM_INV },
1469 { "credential-forwarding", FTS_CFW, 0 },
1470 { "da", FTS_DAT, CM_INV|CM_ABR },
1471 { "data-protection-level", FTS_DPL, 0 },
1472 #endif /* FTP_SECURITY */
1473 { "dates", FTS_DAT, 0 },
1474 { "debug", FTS_DBG, 0 },
1475 { "display", FTS_DIS, 0 },
1477 { "dpl", FTS_DPL, CM_INV },
1478 #endif /* FTP_SECURITY */
1479 { "error-action", FTS_ERR, 0 },
1480 { "filenames", FTS_CNV, 0 },
1481 { "get-filetype-switching", FTS_GFT, 0 },
1482 { "passive-mode", FTS_PSV, 0 },
1483 { "pasv", FTS_PSV, CM_INV },
1484 { "permissions", FTS_PRM, 0 },
1485 { "progress-messages", FTS_TST, 0 },
1486 { "send-port-commands", FTS_SPC, 0 },
1488 { "server-character-set", FTS_CSR, 0 },
1489 #endif /* NOCSETS */
1490 { "server-time-offset", FTS_STO, 0 },
1492 { "srp", FTS_SRP, 0 },
1494 { "srp", FTS_SRP, CM_INV },
1495 #endif /* FTP_SRP */
1497 { "timeout", FTS_TMO, 0 },
1498 #endif /* FTP_TIMEOUT */
1499 { "type", FTS_TYP, 0 },
1500 { "unique-server-names", FTS_USN, 0 },
1501 { "verbose-mode", FTS_VBM, 0 },
1504 static int nftpset = (sizeof(ftpset) / sizeof(struct keytab)) - 1;
1507 GET and PUT switches are approximately the same as Kermit GET and SEND,
1508 and use the same SND_xxx definitions, but hijack a couple for FTP use.
1509 Don't just make up new ones, since the number of SND_xxx options must be
1510 known in advance for the switch-parsing arrays.
1512 #define SND_USN SND_PRO /* /UNIQUE instead of /PROTOCOL */
1513 #define SND_PRM SND_PIP /* /PERMISSIONS instead of /PIPES */
1514 #define SND_TEN SND_CAL /* /TENEX instead of /CALIBRATE */
1516 static struct keytab putswi[] = { /* FTP PUT switch table */
1517 { "/after", SND_AFT, CM_ARG },
1519 { "/array", SND_ARR, CM_ARG },
1520 #endif /* PUTARRAY */
1521 { "/as", SND_ASN, CM_ARG|CM_INV|CM_ABR },
1522 { "/as-name", SND_ASN, CM_ARG },
1523 { "/ascii", SND_TXT, CM_INV },
1524 { "/b", SND_BIN, CM_INV|CM_ABR },
1525 { "/before", SND_BEF, CM_ARG },
1526 { "/binary", SND_BIN, 0 },
1528 { "/command", SND_CMD, CM_PSH },
1529 #endif /* PUTPIPE */
1531 /* This works but it's dangerous */
1533 { "/dates-differ", SND_DIF, CM_INV },
1534 #endif /* DOUPDATE */
1535 #endif /* COMMENT */
1536 { "/delete", SND_DEL, 0 },
1538 { "/dotfiles", SND_DOT, 0 },
1539 #endif /* UNIXOROSK */
1540 { "/error-action", SND_ERR, CM_ARG },
1541 { "/except", SND_EXC, CM_ARG },
1542 { "/filenames", SND_NAM, CM_ARG },
1545 { "/filter", SND_FLT, CM_ARG|CM_PSH },
1547 #endif /* PIPESEND */
1549 { "/followlinks", SND_LNK, 0 },
1550 #endif /* CKSYMLINK */
1552 { "/image", SND_IMG, 0 },
1554 { "/image", SND_BIN, CM_INV },
1556 { "/larger-than", SND_LAR, CM_ARG },
1557 { "/listfile", SND_FIL, CM_ARG },
1559 { "/local-character-set", SND_CSL, CM_ARG },
1560 #endif /* NOCSETS */
1562 { "/move-to", SND_MOV, CM_ARG },
1563 #endif /* CK_TMPDIR */
1564 { "/nobackupfiles", SND_NOB, 0 },
1566 { "/nodotfiles", SND_NOD, 0 },
1567 #endif /* UNIXOROSK */
1569 { "/nofollowlinks", SND_NLK, 0 },
1570 #endif /* CKSYMLINK */
1572 { "/not-after", SND_NAF, CM_ARG },
1573 { "/not-before", SND_NBE, CM_ARG },
1575 { "/permissions", SND_PRM, CM_ARG },
1577 { "/permissions", SND_PRM, CM_ARG|CM_INV },
1579 { "/quiet", SND_SHH, 0 },
1581 { "/recover", SND_RES, 0 },
1582 #endif /* FTP_RESTART */
1584 { "/recursive", SND_REC, 0 },
1585 #endif /* RECURSIVE */
1586 { "/rename-to", SND_REN, CM_ARG },
1588 { "/restart", SND_RES, CM_INV },
1589 #endif /* FTP_RESTART */
1591 { "/server-character-set", SND_CSR, CM_ARG },
1592 #endif /* NOCSETS */
1593 { "/server-rename-to", SND_SRN, CM_ARG },
1594 { "/simulate", SND_SIM, 0 },
1595 { "/since", SND_AFT, CM_INV|CM_ARG },
1596 { "/smaller-than", SND_SMA, CM_ARG },
1598 { "/starting-at", SND_STA, CM_ARG },
1599 #endif /* COMMENT */
1601 { "/subdirectories", SND_REC, CM_INV },
1602 #endif /* RECURSIVE */
1603 { "/tenex", SND_TEN, 0 },
1604 { "/text", SND_TXT, 0 },
1606 { "/transparent", SND_XPA, 0 },
1607 #endif /* NOCSETS */
1608 { "/type", SND_TYP, CM_ARG },
1610 { "/update", SND_UPD, 0 },
1611 #endif /* DOUPDATE */
1612 { "/unique-server-names", SND_USN, 0 },
1615 static int nputswi = (sizeof(putswi) / sizeof(struct keytab)) - 1;
1617 static struct keytab getswi[] = { /* FTP [M]GET switch table */
1618 { "/after", SND_AFT, CM_INV },
1619 { "/as", SND_ASN, CM_ARG|CM_INV|CM_ABR },
1620 { "/as-name", SND_ASN, CM_ARG },
1621 { "/ascii", SND_TXT, CM_INV },
1622 { "/before", SND_BEF, CM_INV },
1623 { "/binary", SND_BIN, 0 },
1624 { "/collision", SND_COL, CM_ARG },
1626 { "/command", SND_CMD, CM_PSH },
1627 #endif /* PUTPIPE */
1628 { "/delete", SND_DEL, 0 },
1629 { "/error-action", SND_ERR, CM_ARG },
1630 { "/except", SND_EXC, CM_ARG },
1631 { "/filenames", SND_NAM, CM_ARG },
1634 { "/filter", SND_FLT, CM_ARG|CM_PSH },
1636 #endif /* PIPESEND */
1638 { "/image", SND_IMG, 0 },
1640 { "/image", SND_BIN, CM_INV },
1642 { "/larger-than", SND_LAR, CM_ARG },
1643 { "/listfile", SND_FIL, CM_ARG },
1645 { "/local-character-set", SND_CSL, CM_ARG },
1646 #endif /* NOCSETS */
1647 { "/match", SND_PAT, CM_ARG },
1648 { "/ml", SND_MLS, CM_INV|CM_ABR },
1649 { "/mls", SND_MLS, CM_INV|CM_ABR },
1650 { "/mlsd", SND_MLS, 0 },
1651 { "/mlst", SND_MLS, CM_INV },
1653 { "/move-to", SND_MOV, CM_ARG },
1654 #endif /* CK_TMPDIR */
1655 { "/namelist", SND_NML, CM_ARG },
1656 { "/nlst", SND_NLS, 0 },
1657 { "/nobackupfiles", SND_NOB, 0 },
1658 { "/nodotfiles", SND_NOD, 0 },
1660 { "/dates-differ", SND_DIF, CM_INV },
1661 #endif /* DOUPDATE */
1662 { "/not-after", SND_NAF, CM_INV },
1663 { "/not-before", SND_NBE, CM_INV },
1664 { "/permissions", SND_PRM, CM_INV },
1665 { "/quiet", SND_SHH, 0 },
1667 { "/recover", SND_RES, 0 },
1668 #endif /* FTP_RESTART */
1670 { "/recursive", SND_REC, 0 },
1671 #endif /* RECURSIVE */
1672 { "/rename-to", SND_REN, CM_ARG },
1674 { "/restart", SND_RES, CM_INV },
1675 #endif /* FTP_RESTART */
1677 { "/server-character-set", SND_CSR, CM_ARG },
1678 #endif /* NOCSETS */
1679 { "/server-rename-to", SND_SRN, CM_ARG },
1680 { "/smaller-than", SND_SMA, CM_ARG },
1682 { "/subdirectories", SND_REC, CM_INV },
1683 #endif /* RECURSIVE */
1684 { "/text", SND_TXT, 0 },
1685 { "/tenex", SND_TEN, 0 },
1687 { "/transparent", SND_XPA, 0 },
1688 #endif /* NOCSETS */
1689 { "/to-screen", SND_MAI, 0 },
1691 { "/update", SND_UPD, CM_INV },
1692 #endif /* DOUPDATE */
1695 static int ngetswi = (sizeof(getswi) / sizeof(struct keytab)) - 1;
1697 static struct keytab delswi[] = { /* FTP [M]DELETE switch table */
1698 { "/error-action", SND_ERR, CM_ARG },
1699 { "/except", SND_EXC, CM_ARG },
1700 { "/filenames", SND_NAM, CM_ARG },
1701 { "/larger-than", SND_LAR, CM_ARG },
1702 { "/nobackupfiles", SND_NOB, 0 },
1704 { "/nodotfiles", SND_NOD, 0 },
1705 #endif /* UNIXOROSK */
1706 { "/quiet", SND_SHH, 0 },
1708 { "/recursive", SND_REC, 0 },
1709 #endif /* RECURSIVE */
1710 { "/smaller-than", SND_SMA, CM_ARG },
1712 { "/subdirectories", SND_REC, CM_INV },
1713 #endif /* RECURSIVE */
1716 static int ndelswi = (sizeof(delswi) / sizeof(struct keytab)) - 1;
1718 static struct keytab fntab[] = { /* Filename conversion keyword table */
1719 { "automatic", 2, CNV_AUTO },
1720 { "converted", 1, CNV_CNV },
1721 { "literal", 0, CNV_LIT }
1723 static int nfntab = (sizeof(fntab) / sizeof(struct keytab));
1725 static struct keytab ftptyp[] = { /* SET FTP TYPE table */
1726 { "ascii", FTT_ASC, 0 },
1727 { "binary", FTT_BIN, 0 },
1728 { "tenex", FTT_TEN, 0 },
1729 { "text", FTT_ASC, CM_INV },
1732 static int nftptyp = (sizeof(ftptyp) / sizeof(struct keytab)) - 1;
1735 static struct keytab ftppro[] = { /* SET FTP PROTECTION-LEVEL table */
1736 { "clear", FPL_CLR, 0 },
1737 { "confidential", FPL_CON, 0 },
1738 { "private", FPL_PRV, 0 },
1739 { "safe", FPL_SAF, 0 },
1742 static int nftppro = (sizeof(ftppro) / sizeof(struct keytab)) - 1;
1743 #endif /* FTP_SECURITY */
1745 /* Definitions for FTP from RFC765. */
1749 #define REPLY_PRELIM 1 /* Positive preliminary */
1750 #define REPLY_COMPLETE 2 /* Positive completion */
1751 #define REPLY_CONTINUE 3 /* Positive intermediate */
1752 #define REPLY_TRANSIENT 4 /* Transient negative completion */
1753 #define REPLY_ERROR 5 /* Permanent negative completion */
1754 #define REPLY_SECURE 6 /* Security encoded message */
1756 /* Form codes and names */
1758 #define FORM_N 1 /* Non-print */
1759 #define FORM_T 2 /* Telnet format effectors */
1760 #define FORM_C 3 /* Carriage control (ASA) */
1762 /* Structure codes and names */
1764 #define STRU_F 1 /* File (no record structure) */
1765 #define STRU_R 2 /* Record structure */
1766 #define STRU_P 3 /* Page structure */
1768 /* Mode types and names */
1770 #define MODE_S 1 /* Stream */
1771 #define MODE_B 2 /* Block */
1772 #define MODE_C 3 /* Compressed */
1774 /* Protection levels and names */
1776 #define PROT_C 1 /* Clear */
1777 #define PROT_S 2 /* Safe */
1778 #define PROT_P 3 /* Private */
1779 #define PROT_E 4 /* Confidential */
1781 #ifdef COMMENT /* Not used */
1783 char *strunames[] = {"0", "File", "Record", "Page" };
1784 char *formnames[] = {"0", "Nonprint", "Telnet", "Carriage-control" };
1785 char *modenames[] = {"0", "Stream", "Block", "Compressed" };
1786 char *levelnames[] = {"0", "Clear", "Safe", "Private", "Confidential" };
1787 #endif /* FTP_NAMES */
1791 #define REC_ESC '\377' /* Record-mode Escape */
1792 #define REC_EOR '\001' /* Record-mode End-of-Record */
1793 #define REC_EOF '\002' /* Record-mode End-of-File */
1797 #define BLK_EOR 0x80 /* Block is End-of-Record */
1798 #define BLK_EOF 0x40 /* Block is End-of-File */
1799 #define BLK_REPLY_ERRORS 0x20 /* Block might have errors */
1800 #define BLK_RESTART 0x10 /* Block is Restart Marker */
1801 #define BLK_BYTECOUNT 2 /* Bytes in this block */
1802 #endif /* COMMENT */
1804 #define RADIX_ENCODE 0 /* radix_encode() function codes */
1805 #define RADIX_DECODE 1
1808 The default setpbsz() value in the Unix FTP client is 1<<20 (1MB). This
1809 results in a serious performance degradation due to the increased number
1810 of page faults and the inability to overlap encrypt/decrypt, file i/o, and
1811 network i/o. So instead we set the value to 1<<13 (8K), about half the size
1812 of the typical TCP window. Maybe we should add a command to allow the value
1815 #define DEFAULT_PBSZ 1<<13
1819 _PROTOTYP(int remtxt, (char **) );
1820 _PROTOTYP(char * gskreason, (int) );
1821 _PROTOTYP(static int ftpclose,(void));
1822 _PROTOTYP(static int zzsend, (int, CHAR));
1823 _PROTOTYP(static int getreply,(int,int,int,int,int));
1824 _PROTOTYP(static int radix_encode,(CHAR[], CHAR[], int, int *, int));
1825 _PROTOTYP(static int setpbsz,(unsigned int));
1826 _PROTOTYP(static int recvrequest,(char *,char *,char *,char *,
1827 int,int,char *,int,int,int));
1828 _PROTOTYP(static int ftpcmd,(char *,char *,int,int,int));
1829 _PROTOTYP(static int fts_cpl,(int));
1830 _PROTOTYP(static int fts_dpl,(int));
1832 _PROTOTYP(static int ftp_auth, (void));
1833 #endif /* FTP_SECURITY */
1834 _PROTOTYP(static int ftp_user, (char *, char *, char *));
1835 _PROTOTYP(static int ftp_login, (char *));
1836 _PROTOTYP(static int ftp_reset, (void));
1837 _PROTOTYP(static int ftp_rename, (char *, char *));
1838 _PROTOTYP(static int ftp_umask, (char *));
1839 _PROTOTYP(static int secure_flush, (int));
1841 _PROTOTYP(static int secure_putc, (char, int));
1842 #endif /* COMMENT */
1843 _PROTOTYP(static int secure_write, (int, CHAR *, unsigned int));
1844 _PROTOTYP(static int scommand, (char *));
1845 _PROTOTYP(static int secure_putbuf, (int, CHAR *, unsigned int));
1846 _PROTOTYP(static int secure_getc, (int, int));
1847 _PROTOTYP(static int secure_getbyte, (int, int));
1848 _PROTOTYP(static int secure_read, (int, char *, int));
1849 _PROTOTYP(static int initconn, (void));
1850 _PROTOTYP(static int dataconn, (char *));
1851 _PROTOTYP(static int setprotbuf,(unsigned int));
1852 _PROTOTYP(static int sendrequest, (char *, char *, char *, int,int,int,int));
1854 _PROTOTYP(static char * radix_error,(int));
1855 _PROTOTYP(static char * ftp_hookup,(char *, int, int));
1856 _PROTOTYP(static CHAR * remote_files, (int, CHAR *, CHAR *, int));
1858 _PROTOTYP(static VOID mlsreset, (void));
1859 _PROTOTYP(static VOID secure_error, (char *fmt, ...));
1860 _PROTOTYP(static VOID lostpeer, (void));
1861 _PROTOTYP(static VOID cancel_remote, (int));
1862 _PROTOTYP(static VOID changetype, (int, int));
1864 _PROTOTYP(static sigtype cmdcancel, (int));
1867 _PROTOTYP(static int srp_reset, ());
1868 _PROTOTYP(static int srp_ftp_auth, (char *,char *,char *));
1869 _PROTOTYP(static int srp_put, (CHAR *, CHAR **, int, int *));
1870 _PROTOTYP(static int srp_get, (CHAR **, CHAR **, int *, int *));
1871 _PROTOTYP(static int srp_encode, (int, CHAR *, CHAR *, unsigned int));
1872 _PROTOTYP(static int srp_decode, (int, CHAR *, CHAR *, unsigned int));
1873 _PROTOTYP(static int srp_selcipher, (char *));
1874 _PROTOTYP(static int srp_selhash, (char *));
1875 #endif /* FTP_SRP */
1878 _PROTOTYP(static void user_gss_error,(OM_uint32, OM_uint32,char *));
1879 #endif /* FTP_GSSAPI */
1881 /* D O F T P A R G -- Do an FTP command-line argument. */
1894 #define FT_SECURE 10
1895 #define FT_VERIFY 11
1897 static struct keytab ftpztab[] = {
1898 { "!gss", FT_NOGSS, 0 },
1899 { "!krb4", FT_NOK4, 0 },
1900 { "!srp", FT_NOSRP, 0 },
1901 { "!ssl", FT_NOSSL, 0 },
1902 { "!tls", FT_NOTLS, 0 },
1903 { "cert", FT_CERTFI, CM_ARG },
1904 { "certsok", FT_OKCERT, 0 },
1905 { "debug", FT_DEBUG, 0 },
1906 { "key", FT_KEY, CM_ARG },
1907 { "nogss", FT_NOGSS, 0 },
1908 { "nokrb4", FT_NOK4, 0 },
1909 { "nosrp", FT_NOSRP, 0 },
1910 { "nossl", FT_NOSSL, 0 },
1911 { "notls", FT_NOTLS, 0 },
1913 { "secure", FT_SECURE, 0 },
1914 #endif /* COMMENT */
1915 { "verify", FT_VERIFY, CM_ARG },
1918 static int nftpztab = sizeof(ftpztab) / sizeof(struct keytab) - 1;
1921 The following cipher and hash tables should be replaced with
1922 dynamicly created versions based upon the linked library.
1924 #define SRP_BLOWFISH_ECB 1
1925 #define SRP_BLOWFISH_CBC 2
1926 #define SRP_BLOWFISH_CFB64 3
1927 #define SRP_BLOWFISH_OFB64 4
1928 #define SRP_CAST5_ECB 5
1929 #define SRP_CAST5_CBC 6
1930 #define SRP_CAST5_CFB64 7
1931 #define SRP_CAST5_OFB64 8
1932 #define SRP_DES_ECB 9
1933 #define SRP_DES_CBC 10
1934 #define SRP_DES_CFB64 11
1935 #define SRP_DES_OFB64 12
1936 #define SRP_DES3_ECB 13
1937 #define SRP_DES3_CBC 14
1938 #define SRP_DES3_CFB64 15
1939 #define SRP_DES3_OFB64 16
1941 static struct keytab ciphertab[] = {
1942 { "blowfish_ecb", SRP_BLOWFISH_ECB, 0 },
1943 { "blowfish_cbc", SRP_BLOWFISH_CBC, 0 },
1944 { "blowfish_cfb64", SRP_BLOWFISH_CFB64, 0 },
1945 { "blowfish_ofb64", SRP_BLOWFISH_OFB64, 0 },
1946 { "cast5_ecb", SRP_CAST5_ECB, 0 },
1947 { "cast5_cbc", SRP_CAST5_CBC, 0 },
1948 { "cast5_cfb64", SRP_CAST5_CFB64, 0 },
1949 { "cast5_ofb64", SRP_CAST5_OFB64, 0 },
1950 { "des_ecb", SRP_DES_ECB, 0 },
1951 { "des_cbc", SRP_DES_CBC, 0 },
1952 { "des_cfb64", SRP_DES_CFB64, 0 },
1953 { "des_ofb64", SRP_DES_OFB64, 0 },
1954 { "des3_ecb", SRP_DES3_ECB, 0 },
1955 { "des3_cbc", SRP_DES3_CBC, 0 },
1956 { "des3_cfb64", SRP_DES3_CFB64, 0 },
1957 { "des3_ofb64", SRP_DES3_OFB64, 0 },
1961 static int nciphertab = sizeof(ciphertab) / sizeof(struct keytab) - 1;
1965 static struct keytab hashtab[] = {
1966 { "md5", SRP_MD5, 0 },
1968 { "sha", SRP_SHA, 0 },
1971 static int nhashtab = sizeof(hashtab) / sizeof(struct keytab) - 1;
1973 #endif /* FTP_SECURITY */
1976 strval(s1,s2) char * s1, * s2; {
1979 return(*s1 ? s1 : (*s2 ? s2 : "(none)"));
1983 static char * rfnptr = NULL;
1984 static int rfnlen = 0;
1985 static char rfnbuf[RFNBUFSIZ]; /* Remote filename translate buffer */
1986 static char * xgnbp = NULL;
1989 strgetc() { /* Helper function for xgnbyte() */
1995 c = (unsigned) *xgnbp++;
1996 return(((unsigned) c) & 0xff);
1999 static int /* Helper function for xpnbyte() */
2004 #endif /* CK_ANSIC */
2006 rfnlen = rfnptr - rfnbuf;
2007 if (rfnlen >= (RFNBUFSIZ - 1))
2019 #endif /* CK_ANSIC */
2026 bytswap(c0,c1) int * c0, * c1; {
2032 #endif /* NOCSETS */
2035 char ftplogbuf[CXLOGBUFL] = { NUL, NUL }; /* Connection Log */
2036 int ftplogactive = 0;
2037 long ftplogprev = 0L;
2042 extern char diafil[];
2043 long d1, d2, t1, t2;
2046 debug(F111,"ftp cx log active",ckitoa(dialog),ftplogactive);
2047 debug(F110,"ftp cx log buf",ftplogbuf,0);
2049 if (!ftplogactive || !ftplogbuf[0]) /* No active record */
2052 ftplogactive = 0; /* Record is not active */
2054 d1 = mjd((char *)ftplogbuf); /* Get start date of this session */
2055 ckstrncpy(buf,ckdate(),31); /* Get current date */
2056 d2 = mjd(buf); /* Convert them to mjds */
2057 p = ftplogbuf; /* Get start time */
2059 p[14] = NUL; /* Convert to seconds */
2060 t1 = atol(p+9) * 3600L + atol(p+12) * 60L + atol(p+15);
2063 p = buf; /* Get end time */
2066 t2 = atol(p+9) * 3600L + atol(p+12) * 60L + atol(p+15);
2067 t2 = ((d2 - d1) * 86400L) + (t2 - t1); /* Compute elapsed time */
2071 ckstrncat(ftplogbuf,"E=",CXLOGBUFL); /* Append to log record */
2072 ckstrncat(ftplogbuf,p,CXLOGBUFL);
2075 debug(F101,"ftp cx log dialog","",dialog);
2076 if (dialog) { /* If logging */
2078 x = diaopn(diafil,1,1); /* Open log in append mode */
2080 debug(F101,"ftp cx log open","",x);
2081 x = zsoutl(ZDIFIL,ftplogbuf); /* Write the record */
2082 debug(F101,"ftp cx log write","",x);
2083 x = zclose(ZDIFIL); /* Close the log */
2084 debug(F101,"ftp cx log close","",x);
2091 ftplogend(); /* Previous session not closed out? */
2093 ftplogactive = 1; /* Record is active */
2095 ckmakxmsg(ftplogbuf,CXLOGBUFL,
2096 ckdate()," ",strval(ftp_logname,NULL)," ",ckgetpid(),
2097 " T=FTP N=", strval(ftp_host,NULL)," H=",myhost,
2098 " P=", ckitoa(ftp_port)," "); /* SMS 2007/02/15 */
2099 debug(F110,"ftp cx log begin",ftplogbuf,0);
2101 #endif /* CKLOGDIAL */
2103 static char * dummy[2] = { NULL, NULL };
2105 static struct keytab modetab[] = {
2111 int /* Called from ckuusy.c */
2116 #endif /* CK_ANSIC */
2120 extern char **xargv, *xarg0;
2121 extern int xargc, stayflg, haveftpuid;
2122 extern char uidbuf[];
2124 xp = *xargv+1; /* Pointer for bundled args */
2126 if (ckstrchr("MuDPkcHzm",c)) { /* Options that take arguments */
2128 fatal("?Invalid argument bundling");
2131 if ((xargc < 1) || (**xargv == '-')) {
2132 fatal("?Required argument missing");
2135 switch (c) { /* Big switch on arg */
2136 case 'h': /* help */
2137 printf("C-Kermit's FTP client command-line personality. Usage:\n");
2138 printf(" %s [ options ] host [ port ] [-pg files ]\n\n",xarg0);
2139 printf("Options:\n");
2140 printf(" -h = help (this message)\n");
2141 printf(" -m mode = \"passive\" (default) or \"active\"\n");
2142 printf(" -u name = username for autologin (or -M)\n");
2143 printf(" -P password = password for autologin (RISKY)\n");
2144 printf(" -A = autologin anonymously\n");
2145 printf(" -D directory = cd after autologin\n");
2146 printf(" -b = force binary mode\n");
2147 printf(" -a = force text (\"ascii\") mode (or -T)\n");
2148 printf(" -d = debug (double to add timestamps)\n");
2149 printf(" -n = no autologin\n");
2150 printf(" -v = verbose (default)\n");
2151 printf(" -q = quiet\n");
2152 printf(" -S = Stay (issue command prompt when done)\n");
2153 printf(" -Y = do not execute Kermit init file\n");
2154 printf(" -p files = files to put after autologin (or -s)\n");
2155 printf(" -g files = files to get after autologin\n");
2156 printf(" -R = recursive (for use with -p)\n");
2159 printf("\nSecurity options:\n");
2160 printf(" -k realm = Kerberos 4 realm\n");
2161 printf(" -f = Kerboros 5 credentials forwarding\n");
2162 printf(" -x = autoencryption mode\n");
2163 printf(" -c cipher = SRP cipher type\n");
2164 printf(" -H hash = SRP encryption hash\n");
2165 printf(" -z option = Security options\n");
2166 #endif /* FTP_SECURITY */
2168 printf("\n-p or -g, if given, should be last. Example:\n");
2169 printf(" ftp -A kermit.columbia.edu -D kermit -ag TESTFILE\n");
2171 doexit(GOOD_EXIT,-1);
2174 case 'R': /* Recursive */
2178 case 'd': /* Debug */
2184 deblog = debopn("debug.log",0);
2188 /* fall thru on purpose */
2190 case 't': /* Trace */
2194 case 'n': /* No autologin */
2198 case 'i': /* No prompt */
2199 case 'v': /* Verbose */
2200 break; /* (ignored) */
2202 case 'q': /* Quiet */
2206 case 'S': /* Stay */
2211 case 'u': /* My User Name */
2212 if ((int)strlen(*xargv) > 63) {
2213 fatal("username too long");
2215 ckstrncpy(uidbuf,*xargv,UIDBUFLEN);
2220 ckstrncpy(uidbuf,"anonymous",UIDBUFLEN);
2224 case 'T': /* Text */
2225 case 'a': /* "ascii" */
2226 case 'b': /* Binary */
2227 binary = (c == 'b') ? FTT_BIN : FTT_ASC;
2228 ftp_xfermode = XMODE_M;
2235 case 's': { /* Send (= Put) */
2238 fatal("Only one FTP action at a time please");
2241 fatal("invalid argument bundling after -s");
2243 nfils = 0; /* Initialize file counter */
2244 havefiles = 0; /* Assume nothing to send */
2245 cmlist = xargv + 1; /* Remember this pointer */
2247 while (++xargv, --xargc > 0) { /* Traverse the list */
2254 if (!strcmp(*xargv,".")) {
2259 #endif /* RECURSIVE */
2260 if ((rc = zchki(*xargv)) > -1 || (rc == -2)) {
2264 } else if (iswild(*xargv) && nzxpand(*xargv,0) > 0) {
2269 xargc++, xargv--; /* Adjust argv/argc */
2272 fatal("No files to put");
2274 fatal("No files to get");
2280 case 'D': /* Directory */
2281 makestr(&ftp_rdir,*xargv);
2284 case 'm': /* Mode (Active/Passive */
2285 ftp_psv = lookup(modetab,*xargv,2,NULL);
2286 if (ftp_psv < 0) fatal("Invalid mode");
2290 makestr(&ftp_tmp,*xargv); /* You-Know-What */
2293 case 'Y': /* No initialization file */
2294 break; /* (already done in prescan) */
2297 case 'U': { /* URL */
2298 /* These are set by urlparse() - any not set are NULL */
2301 Kermit has accepted host:port notation since many years before URLs were
2302 invented. Unfortunately, URLs conflict with this notation. Thus "ftp
2303 host:449" looks like a URL and results in service = host and host = 449.
2304 Here we try to catch this situation transparently to the user.
2306 if (ckstrcmp(g_url.svc,"ftp",-1,0)
2308 && ckstrcmp(g_url.svc,"ftps",-1,0)
2315 g_url.por = g_url.hos;
2316 g_url.hos = g_url.svc;
2319 ckmakmsg(tmpbuf,TMPBUFSIZ,"Non-FTP URL: service=",
2320 g_url.svc," host=",g_url.hos);
2324 makestr(&ftp_host,g_url.hos);
2327 ckstrncpy(uidbuf,g_url.usr,UIDBUFLEN);
2328 makestr(&ftp_logname,uidbuf);
2331 makestr(&ftp_tmp,g_url.psw);
2336 ckstrncpy(uidbuf,"anonymous",UIDBUFLEN);
2337 makestr(&ftp_logname,uidbuf);
2340 fatal("Only one FTP action at a time please");
2345 dummy[0] = g_url.pth;
2357 case 'k': { /* K4 Realm */
2359 ckstrncpy(ftp_realm,*xargv, REALM_SZ);
2360 #endif /* FTP_KRB4 */
2361 if (ftp_deb) printf("K4 Realm = [%s]\n",*xargv);
2367 if (ftp_deb) printf("K5 Credentials Forwarding\n");
2368 #else /* FTP_GSSAPI */
2369 printf("K5 Credentials Forwarding not supported\n");
2370 #endif /* FTP_GSSAPI */
2375 if (ftp_deb) printf("Autoencryption\n");
2378 case 'c': { /* Cipher */
2380 if (!srp_selcipher(*xargv)) {
2381 if (ftp_deb) printf("SRP cipher type: \"%s\"\n",*xargv);
2383 printf("?Invalid SRP cipher type: \"%s\"\n",*xargv);
2385 printf("?SRP not supported\n");
2386 #endif /* FTP_SRP */
2391 if (!srp_selhash(*xargv)) {
2392 if (ftp_deb) printf("SRP hash type: \"%s\"\n",*xargv);
2394 printf("?Invalid SRP hash type: \"%s\"\n",*xargv);
2396 printf("?SRP not supported\n");
2397 #endif /* FTP_SRP */
2401 /* *xargv contains a value of the form tag=value */
2402 /* we need to lookup the tag and save the value */
2403 char * p = NULL, * q = NULL;
2405 y = ckindex("=",p,0,0,1);
2408 x = lookup(ftpztab,p,nftpztab,&z);
2410 printf("?Invalid security option: \"%s\"\n",p);
2413 printf("Security option: \"%s",p);
2414 if (ftpztab[z].flgs & CM_ARG) {
2416 fatal("?Missing required value");
2419 fatal("?Missing required value");
2423 switch (ftpztab[z].kwval) { /* -z options w/args */
2426 for (z = 0; z < FTPATYPS && ftp_auth_type[z]; z++) {
2427 if (ftp_auth_type[z] == FTA_GK5) {
2429 y < (FTPATYPS-1) && ftp_auth_type[y];
2432 ftp_auth_type[y] = ftp_auth_type[y+1];
2433 ftp_auth_type[FTPATYPS-1] = 0;
2437 #endif /* FTP_GSSAPI */
2441 for (z = 0; z < FTPATYPS && ftp_auth_type[z]; z++) {
2442 if (ftp_auth_type[z] == FTA_K4) {
2444 y < (FTPATYPS-1) && ftp_auth_type[y];
2447 ftp_auth_type[y] = ftp_auth_type[y+1];
2448 ftp_auth_type[FTPATYPS-1] = 0;
2452 #endif /* FTP_KRB4 */
2456 for (z = 0; z < FTPATYPS && ftp_auth_type[z]; z++) {
2457 if (ftp_auth_type[z] == FTA_SRP) {
2459 y < (FTPATYPS-1) && ftp_auth_type[y];
2462 ftp_auth_type[y] = ftp_auth_type[y+1];
2463 ftp_auth_type[FTPATYPS-1] = 0;
2467 #endif /* FTP_SRP */
2471 for (z = 0; z < FTPATYPS && ftp_auth_type[z]; z++) {
2472 if (ftp_auth_type[z] == FTA_SSL) {
2474 y < (FTPATYPS-1) && ftp_auth_type[y];
2477 ftp_auth_type[y] = ftp_auth_type[y+1];
2478 ftp_auth_type[FTPATYPS-1] = 0;
2486 for (z = 0; z < FTPATYPS && ftp_auth_type[z]; z++) {
2487 if (ftp_auth_type[z] == FTA_TLS) {
2489 y < (FTPATYPS-1) && ftp_auth_type[y];
2492 ftp_auth_type[y] = ftp_auth_type[y+1];
2493 ftp_auth_type[FTPATYPS-1] = 0;
2501 makestr(&ssl_rsa_cert_file,q);
2506 ssl_certsok_flag = 1;
2515 deblog = debopn("debug.log",0);
2521 makestr(&ssl_rsa_key_file,q);
2530 printf("?Bad number: %s\n",q);
2531 ssl_verify_flag = atoi(q);
2536 if (ftp_deb) printf("\"\n");
2540 #endif /* FTP_SECURITY */
2544 "unknown command-line option, type \"ftp -h\" for help"
2548 c = *++xp; /* See if options are bundled */
2561 return(connected ? loggedin : 0);
2566 return((ftp_dpl == FPL_CLR && !ssl_ftp_proxy) ? 0 : 1);
2570 ftscreen(n, c, z, s) int n; char c; CK_OFF_T z; char * s; {
2571 if (displa && fdispla && !backgrd && !quiet && !out2screen) {
2573 ckscreen(SCR_PT,'S',(CK_OFF_T)0,"");
2581 /* g m s t i m e r -- Millisecond timer */
2586 /* For those versions of ztime() that also set global ztmsec. */
2591 if (!*p) return(0L);
2592 z = atol(p+11) * 3600L + atol(p+14) * 60L + atol(p+17);
2593 return(z * 1000 + ztmsec);
2595 return((long)time(NULL) * 1000L);
2596 #endif /* HAVE_MSECS */
2600 /* d o s e t f t p -- The SET FTP command */
2605 if ((cx = cmkey(ftpset,nftpset,"","",xxstring)) < 0) /* Set what? */
2609 case FTS_FNC: /* Filename collision action */
2610 if ((x = cmkey(ftpcolxtab,nftpcolx,"","",xxstring)) < 0)
2612 if ((y = cmcfm()) < 0)
2617 case FTS_CNV: /* Filename conversion */
2618 if ((x = cmkey(fntab,nfntab,"","automatic",xxstring)) < 0)
2620 if ((y = cmcfm()) < 0)
2625 case FTS_DBG: /* Debug messages */
2626 return(seton(&ftp_deb));
2628 case FTS_LOG: /* Auto-login */
2629 return(seton(&ftp_log));
2631 case FTS_PSV: /* Passive mode */
2632 return(dosetftppsv());
2634 case FTS_SPC: /* Send port commands */
2635 x = seton(&ftp_spc);
2636 if (x > 0) sendport = ftp_spc;
2639 case FTS_TYP: /* Type */
2640 if ((x = cmkey(ftptyp,nftptyp,"","",xxstring)) < 0)
2642 if ((y = cmcfm()) < 0) return(y);
2645 tenex = (ftp_typ == FTT_TEN);
2648 case FTS_USN: /* Unique server names */
2649 return(seton(&ftp_usn));
2651 case FTS_VBM: /* Verbose mode */
2652 if ((x = seton(&ftp_vbm)) < 0) /* Per-command copy */
2654 ftp_vbx = ftp_vbm; /* Global sticky copy */
2657 case FTS_TST: /* "if (testing)" messages */
2658 return(seton(&testing));
2660 case FTS_PRM: /* Send permissions */
2661 return(setonaut(&ftp_prm));
2663 case FTS_AUT: /* Auto-authentication */
2664 return(seton(&ftp_aut));
2666 case FTS_ERR: /* Error action */
2667 if ((x = cmkey(qorp,2,"","",xxstring)) < 0)
2669 if ((y = cmcfm()) < 0)
2672 return(success = 1);
2675 case FTS_XLA: /* Translation */
2676 return(seton(&ftp_xla));
2678 case FTS_CSR: /* Server charset */
2679 if ((x = cmkey(fcstab,nfilc,"character-set","utf8",xxstring)) < 0)
2681 if ((y = cmcfm()) < 0)
2684 ftp_xla = 1; /* Also enable translation */
2685 return(success = 1);
2686 #endif /* NOCSETS */
2689 return(seton(&get_auto)); /* GET-filetype-switching */
2692 return(seton(&ftp_dates)); /* Set file dates */
2695 case FTS_TMO: /* Timeout */
2696 if ((x = cmnum("Number of seconds","0",10,&z,xxstring)) < 0)
2698 if ((y = cmcfm()) < 0)
2701 return(success = 1);
2702 #endif /* FTP_TIMEOUT */
2704 case FTS_STO: { /* Server time offset */
2705 char * s, * p = NULL;
2707 if ((x = cmfld("[+-]hh[:mm[:ss]]","+0",&s,xxstring)) < 0)
2709 if (!strcmp(s,"+0")) {
2711 } else if ((x = delta2sec(s,&k)) < 0) { /* Check format */
2712 printf("?Invalid time offset\n");
2715 makestr(&p,s); /* Make a safe copy the string */
2716 if ((x = cmcfm()) < 0) { /* Get confirmation */
2721 fts_sto = p; /* Confirmed - set the string. */
2722 return(success = 1);
2726 if ((x = cmtxt("Text", "", &s, xxstring)) < 0)
2728 makestr(&ftp_apw, *s ? s : NULL);
2729 return(success = 1);
2733 if ((x = cmkey(ftpbugtab,nftpbug,"","",xxstring)) < 0)
2738 return seton(&ftp_bug_use_ssl_v2);
2746 case FTS_CRY: /* Auto-encryption */
2747 return(seton(&ftp_cry));
2749 case FTS_CFW: /* Credential-forwarding */
2750 return(seton(&ftp_cfw));
2752 case FTS_CPL: /* Command protection level */
2753 if ((x = cmkey(ftppro,nftppro,"","",xxstring)) < 0) return(x);
2754 if ((y = cmcfm()) < 0) return(y);
2755 success = fts_cpl(x);
2758 case FTS_DPL: /* Data protection level */
2759 if ((x = cmkey(ftppro,nftppro,"","",xxstring)) < 0) return(x);
2760 if ((y = cmcfm()) < 0) return(y);
2761 success = fts_dpl(x);
2764 case FTS_ATP: { /* FTP Auth Type */
2765 int i, j, atypes[8];
2767 for (i = 0; i < 8; i++) {
2768 if ((y = cmkey(ftpauth,nftpauth,"",
2769 (i == 0) ? "automatic" : "",
2775 if (i > 0 && (y == FTA_AUTO)) {
2776 printf("?Choice may only be used in first position.\r\n");
2779 for (j = 0; j < i; j++) {
2780 if (atypes[j] == y) {
2781 printf("\r\n?Choice has already been used.\r\n");
2786 if (y == FTA_AUTO) {
2793 if ((z = cmcfm()) < 0)
2795 if (atypes[0] == FTA_AUTO) {
2798 ftp_auth_type[i++] = FTA_GK5;
2799 #endif /* FTP_GSSAPI */
2801 ftp_auth_type[i++] = FTA_SRP;
2802 #endif /* FTP_SRP */
2804 ftp_auth_type[i++] = FTA_K4;
2805 #endif /* FTP_KRB4 */
2807 ftp_auth_type[i++] = FTA_TLS;
2808 ftp_auth_type[i++] = FTA_SSL;
2810 ftp_auth_type[i] = 0;
2812 for (i = 0; i < 8; i++)
2813 ftp_auth_type[i] = atypes[i];
2815 return(success = 1);
2820 if ((x = cmkey(ftpsrp,nftpsrp,"","",xxstring)) < 0)
2824 if ((x = cmkey(ciphertab,nciphertab,"","",xxstring)) < 0)
2826 if ((z = cmcfm()) < 0)
2828 success = !srp_selcipher(ciphertab[x].kwd);
2831 if ((x = cmkey(hashtab,nhashtab,"","",xxstring)) < 0)
2833 if ((z = cmcfm()) < 0)
2835 success = !srp_selhash(hashtab[x].kwd);
2836 return(success = 1);
2838 if ((z = cmcfm()) < 0)
2843 if ((z = cmcfm()) < 0)
2846 #endif /* FTP_SRP */
2847 #endif /* FTP_SECURITY */
2850 doxdis(2); /* 2 == ftp */
2851 return(success = 1);
2864 printf(" ftp closing %s...\n",ftp_host);
2866 return((x > -1) ? 1 : 0);
2869 /* o p e n f t p -- Parse FTP hostname & port and open */
2872 openftp(s,opn_tls) char * s; int opn_tls; {
2873 char c, * p, * hostname = NULL, *hostsave = NULL, * service = NULL;
2874 int i, n, havehost = 0, getval = 0, rc = -9, opn_psv = -1, nologin = 0;
2876 struct FDB sw, fl, cm;
2877 extern int nnetdir; /* Network services directory */
2878 extern int nhcount; /* Lookup result */
2879 extern char *nh_p[]; /* Network directory entry pointers */
2880 extern char *nh_p2[]; /* Network directory entry nettype */
2883 if (!*s) return(-2);
2885 makestr(&hostname,s);
2886 hostsave = hostname;
2887 makestr(&ftp_logname,NULL);
2891 debug(F110,"ftp open",hostname,0);
2893 if (sav_psv > -1) { /* Restore prevailing active/passive */
2894 ftp_psv = sav_psv; /* selection in case it was */
2895 sav_psv = -1; /* temporarily overriden by a switch */
2897 if (sav_log > -1) { /* Ditto for autologin */
2901 cmfdbi(&sw, /* Switches */
2903 "Service name or port;\n or switch",
2905 "", /* addtl string data */
2906 nftpswi, /* addtl numeric data 1: tbl size */
2907 4, /* addtl numeric data 2: none */
2908 xxstring, /* Processing function */
2909 ftpswitab, /* Keyword table */
2910 &fl /* Pointer to next FDB */
2912 cmfdbi(&fl, /* A host name or address */
2915 "xYzBoo", /* default */
2916 "", /* addtl string data */
2917 0, /* addtl numeric data 1 */
2918 0, /* addtl numeric data 2 */
2923 cmfdbi(&cm, /* Command confirmation */
2936 rc = cmfdb(&sw); /* Parse a service name or a switch */
2940 if (cmresult.fcode == _CMCFM) { /* Done? */
2942 } else if (cmresult.fcode == _CMFLD) { /* Port */
2943 if (ckstrcmp("xYzBoo",cmresult.sresult,-1,1))
2944 makestr(&service,cmresult.sresult);
2946 makestr(&service,opn_tls?"ftps":"ftp");
2947 } else if (cmresult.fcode == _CMKEY) { /* Have a switch */
2948 c = cmgbrk(); /* get break character */
2949 getval = (c == ':' || c == '=');
2951 if (getval && !(cmresult.kflags & CM_ARG)) {
2952 printf("?This switch does not take arguments\n");
2955 if (!getval && (cmresult.kflags & CM_ARG)) {
2956 printf("?This switch requires an argument\n");
2959 switch (cmresult.nresult) { /* Switch */
2960 case OPN_ANO: /* /ANONYMOUS */
2964 case OPN_NIN: /* /NOINIT */
2967 case OPN_NOL: /* /NOLOGIN */
2970 makestr(&ftp_logname,NULL);
2972 case OPN_PSW: /* /PASSWORD */
2973 if (!anonymous) /* Don't log real passwords */
2975 rc = cmfld("Password for FTP server","",&p,xxstring);
2977 makestr(&ftp_tmp,NULL);
2978 } else if (rc < 0) {
2981 makestr(&ftp_tmp,brstrip(p));
2985 case OPN_USR: /* /USER */
2986 rc = cmfld("Username for FTP server","",&p,xxstring);
2988 makestr(&ftp_logname,NULL);
2989 } else if (rc < 0) {
2995 makestr(&ftp_logname,brstrip(p));
2999 rc = cmfld("Account for FTP server","",&p,xxstring);
3001 makestr(&ftp_acc,NULL);
3002 } else if (rc < 0) {
3005 makestr(&ftp_acc,brstrip(p));
3021 if (n == 0) { /* After first time through */
3022 cmfdbi(&sw, /* accept only switches */
3024 "\nCarriage return to confirm to command, or switch",
3036 debug(F100,"ftp openftp while exit","",0);
3038 debug(F101,"ftp openftp cmcfm rc","",rc);
3041 #endif /* COMMENT */
3043 if (opn_psv > -1) { /* /PASSIVE or /ACTIVE switch given */
3047 if (nologin || haveuser) { /* /NOLOGIN or /USER switch given */
3049 ftp_log = haveuser ? 1 : 0;
3051 if (*hostname == '=') { /* Bypass directory lookup */
3052 hostname++; /* if hostname starts with '=' */
3054 } else if (isdigit(*hostname)) { /* or if it starts with a digit */
3058 makestr(&service,opn_tls?"ftps":"ftp");
3061 if (!havehost && nnetdir > 0) { /* If there is a networks directory */
3062 lunet(hostname); /* Look up the name */
3063 debug(F111,"ftp openftp lunet",hostname,nhcount);
3066 printf(" ftp open trying \"%s %s\"...\n",hostname,service);
3067 success = ftpopen(hostname,service,opn_tls);
3068 debug(F101,"ftp openftp A ftpopen success","",success);
3072 for (i = 0; i < nhcount; i++) {
3073 if (nh_p2[i]) /* If network type specified */
3074 if (ckstrcmp(nh_p2[i],"tcp/ip",strlen(nh_p2[i]),0))
3077 makestr(&hostname,nh_p[i]);
3078 debug(F111,"ftpopen lunet substitution",hostname,i);
3080 printf(" ftp open trying \"%s %s\"...\n",hostname,service);
3081 success = ftpopen(hostname,service,opn_tls);
3082 debug(F101,"ftp openftp B ftpopen success","",success);
3087 if (!found) { /* E.g. if no network types match */
3089 printf(" ftp open trying \"%s %s\"...\n",hostname,service);
3090 success = ftpopen(hostname,service,opn_tls);
3091 debug(F101,"ftp openftp C ftpopen success","",success);
3098 printf(" ftp open trying \"%s %s\"...\n",hostname,service);
3099 success = ftpopen(hostname,service,opn_tls);
3100 debug(F111,"ftp openftp D ftpopen success",hostname,success);
3101 debug(F111,"ftp openftp D ftpopen connected",hostname,connected);
3108 debug(F101,"ftp openftp xopenftp rc","",rc);
3109 if (hostsave) free(hostsave);
3110 if (service) free(service);
3111 if (rc < 0 && ftp_logname) {
3122 VOID /* 12 Aug 2007 */
3123 doftpglobaltype(x) int x; {
3124 ftp_xfermode = XMODE_M; /* Set manual FTP transfer mode */
3125 ftp_typ = x; /* Used by top-level BINARY and */
3126 g_ftp_typ = x; /* ASCII commands. */
3135 if ((x = cmtxt("Remote account", "", &s, xxstring)) < 0)
3138 makestr(&ftp_acc,brstrip(s));
3140 printf(" ftp account: \"%s\"\n",ftp_acc);
3141 success = (ftpcmd("ACCT",ftp_acc,-1,-1,ftp_vbm) == REPLY_COMPLETE);
3146 doftpusr() { /* Log in as USER */
3147 extern char uidbuf[];
3148 extern char pwbuf[];
3149 extern int pwflg, pwcrypt;
3151 char *s, * acct = "";
3153 debok = 0; /* Don't log */
3155 if ((x = cmfld("Remote username or ID",uidbuf,&s,xxstring)) < 0)
3157 ckstrncpy(line,brstrip(s),LINBUFSIZ); /* brstrip: 15 Jan 2003 */
3158 if ((x = cmfld("Remote password","",&s,xxstring)) < 0) {
3159 if (x == -3) { /* no input */
3160 if ( pwbuf[0] && pwflg ) {
3161 ckstrncpy(tmpbuf,(char *)pwbuf,TMPBUFSIZ);
3164 ck_encrypt((char *)tmpbuf);
3171 ckstrncpy(tmpbuf,brstrip(s),TMPBUFSIZ);
3173 if ((x = cmtxt("Remote account\n or Enter or CR to confirm the command",
3174 "", &s, xxstring)) < 0)
3180 acct = &tmpbuf[x+2];
3181 ckstrncpy(acct,brstrip(s),TMPBUFSIZ - x - 2);
3185 printf(" ftp user \"%s\" password \"%s\"...\n",line,tmpbuf);
3186 success = ftp_user(line,tmpbuf,acct);
3189 #endif /* CKLOGDIAL */
3193 /* DO (various FTP commands)... */
3196 doftptyp(type) int type; { /* TYPE */
3199 changetype(ftp_typ,ftp_vbm);
3200 debug(F101,"doftptyp changed type","",type);
3205 doftpxmkd(s,vbm) char * s; int vbm; { /* MKDIR action */
3206 int lcs = -1, rcs = -1;
3210 if (lcs < 0) lcs = fcharset;
3212 if (rcs < 0) rcs = ftp_csr;
3214 #endif /* NOCSETS */
3215 debug(F110,"ftp doftpmkd",s,0);
3216 if (ftpcmd("MKD",s,lcs,rcs,vbm) == REPLY_COMPLETE)
3217 return(success = 1);
3218 if (ftpcode == 500 || ftpcode == 502) {
3220 printf("MKD command not recognized, trying XMKD\n");
3221 if (ftpcmd("XMKD",s,lcs,rcs,vbm) == REPLY_COMPLETE)
3222 return(success = 1);
3224 return(success = 0);
3228 doftpmkd() { /* MKDIR parse */
3231 if ((x = cmtxt("Remote directory name", "", &s, xxstring)) < 0)
3234 ckstrncpy(line,s,LINBUFSIZ);
3236 printf(" ftp mkdir \"%s\"...\n",line);
3237 return(success = doftpxmkd(line,-1));
3241 doftprmd() { /* RMDIR */
3242 int x, lcs = -1, rcs = -1;
3244 if ((x = cmtxt("Remote directory", "", &s, xxstring)) < 0)
3247 ckstrncpy(line,s,LINBUFSIZ);
3249 printf(" ftp rmdir \"%s\"...\n",line);
3253 if (lcs < 0) lcs = fcharset;
3255 if (rcs < 0) rcs = ftp_csr;
3257 #endif /* NOCSETS */
3258 if (ftpcmd("RMD",line,lcs,rcs,ftp_vbm) == REPLY_COMPLETE)
3259 return(success = 1);
3260 if (ftpcode == 500 || ftpcode == 502) {
3262 printf("RMD command not recognized, trying XMKD\n");
3263 success = (ftpcmd("XRMD",line,lcs,rcs,ftp_vbm) == REPLY_COMPLETE);
3270 doftpren() { /* RENAME */
3273 if ((x = cmfld("Remote filename","",&s,xxstring)) < 0)
3275 ckstrncpy(line,s,LINBUFSIZ);
3276 if ((x = cmfld("New name for remote file","",&s,xxstring)) < 0)
3278 ckstrncpy(tmpbuf,s,TMPBUFSIZ);
3279 if ((x = cmcfm()) < 0)
3283 printf(" ftp rename \"%s\" (to) \"%s\"...\n",line,tmpbuf);
3284 success = ftp_rename(line,tmpbuf);
3289 doftpres() { /* RESET (log out without close) */
3291 if ((x = cmcfm()) < 0)
3295 printf(" ftp reset...\n");
3296 return(success = ftp_reset());
3300 doftpxhlp() { /* HELP */
3303 if ((x = cmtxt("Command name", "", &s, xxstring)) < 0)
3306 ckstrncpy(line,s,LINBUFSIZ);
3308 printf(" ftp help \"%s\"...\n",line);
3309 /* No need to translate -- all FTP commands are ASCII */
3310 return(success = (ftpcmd("HELP",line,0,0,1) == REPLY_COMPLETE));
3314 doftpdir(cx) int cx; { /* [V]DIRECTORY */
3315 int x, lcs = 0, rcs = 0, xlate = 0;
3316 char * p, * s, * m = "";
3317 if (cx == FTP_VDI) {
3318 switch (servertype) {
3329 if ((x = cmtxt("Remote filespec",m,&s,xxstring)) < 0)
3331 if ((x = remtxt(&s)) < 0)
3337 #endif /* NOCSETS */
3339 ckstrncpy(line,s,LINBUFSIZ);
3344 if (xlate) { /* SET FTP CHARACTER-SET-TRANSLATION */
3345 lcs = ftp_csl; /* Local charset */
3346 if (lcs < 0) lcs = fcharset;
3347 if (lcs < 0) xlate = 0;
3349 if (xlate) { /* Still ON? */
3350 rcs = ftp_csx; /* Remote (Server) charset */
3351 if (rcs < 0) rcs = ftp_csr;
3352 if (rcs < 0) xlate = 0;
3354 #endif /* NOCSETS */
3360 printf("Directory of files %s at %s:\n", line, ftp_host);
3362 printf("Directory of files at %s:\n", ftp_host);
3364 debug(F111,"doftpdir",s,cx);
3366 if (cx == FTP_DIR) {
3367 /* Translation of line[] is done inside recvrequest() */
3368 /* when it calls ftpcmd(). */
3370 (recvrequest("LIST","-",s,"wb",0,0,NULL,xlate,lcs,rcs) == 0));
3372 success = 1; /* VDIR - one file at a time... */
3373 p = (char *)remote_files(1,(CHAR *)s,NULL,0); /* Get the file list */
3375 if (!ftp_vbm && !quiet)
3377 while (p && !cancelfile && !cancelgroup) { /* STAT one file */
3378 if (ftpcmd("STAT",p,lcs,rcs,ftp_vbm) < 0) {
3382 p = (char *)remote_files(0,NULL,NULL,0); /* Get next file */
3383 debug(F110,"ftp vdir file",s,0);
3389 doftppwd() { /* PWD */
3390 int x, lcs = -1, rcs = -1;
3394 if (lcs < 0) lcs = fcharset;
3396 if (rcs < 0) rcs = ftp_csr;
3398 #endif /* NOCSETS */
3399 if ((x = cmcfm()) < 0)
3402 if (ftpcmd("PWD",NULL,lcs,rcs,1) == REPLY_COMPLETE) {
3404 } else if (ftpcode == 500 || ftpcode == 502) {
3406 printf("PWD command not recognized, trying XPWD\n");
3407 success = (ftpcmd("XPWD",NULL,lcs,rcs,1) == REPLY_COMPLETE);
3413 doftpcwd(s,vbm) char * s; int vbm; { /* CD (CWD) */
3414 int lcs = -1, rcs = -1;
3418 if (lcs < 0) lcs = fcharset;
3420 if (rcs < 0) rcs = ftp_csr;
3422 #endif /* NOCSETS */
3424 debug(F110,"ftp doftpcwd",s,0);
3425 if (ftpcmd("CWD",s,lcs,rcs,vbm) == REPLY_COMPLETE)
3426 return(success = 1);
3427 if (ftpcode == 500 || ftpcode == 502) {
3429 printf("CWD command not recognized, trying XCWD\n");
3430 if (ftpcmd("XCWD",s,lcs,rcs,vbm) == REPLY_COMPLETE)
3431 return(success = 1);
3433 return(success = 0);
3437 doftpcdup() { /* CDUP */
3438 debug(F100,"ftp doftpcdup","",0);
3439 if (ftpcmd("CDUP",NULL,0,0,1) == REPLY_COMPLETE)
3440 return(success = 1);
3441 if (ftpcode == 500 || ftpcode == 502) {
3443 printf("CDUP command not recognized, trying XCUP\n");
3444 if (ftpcmd("XCUP",NULL,0,0,1) == REPLY_COMPLETE)
3445 return(success = 1);
3447 return(success = 0);
3450 /* s y n c d i r -- Synchronizes client & server directories */
3454 local = pointer to pathname of local file to be sent.
3455 sim = 1 for simulation, 0 for real uploading.
3456 Returns 0 on failure, 1 on success.
3458 The 'local' argument is relative to the initial directory of the MPUT,
3459 i.e. the root of the tree being uploaded. If the directory of the
3460 argument file is different from the directory of the previous file
3461 (which is stored in global putpath[]), this routine does the appropriate
3462 CWDs, CDUPs, and/or MKDIRs to position the FTP server in the same place.
3464 static int cdlevel = 0, cdsimlvl = 0; /* Tree-level trackers */
3467 syncdir(local,sim) char * local; int sim; {
3468 char buf[CKMAXPATH+1];
3469 char tmp[CKMAXPATH+1];
3470 char msgbuf[CKMAXPATH+64];
3471 char c, * p = local, * s = buf, * q = buf, * psep, * ssep;
3472 int i, k = 0, done = 0, itsadir = 0, saveq;
3474 debug(F110,"ftp syncdir local (new)",local,0);
3475 debug(F110,"ftp syncdir putpath (old)",putpath,0);
3477 itsadir = isdir(local); /* Is the local file a directory? */
3480 while ((*s = *p)) { /* Copy the argument filename */
3481 if (++k == CKMAXPATH) /* so we can poke it. */
3483 if (*s == '/') /* Pointer to rightmost dirsep */
3488 if (!itsadir) /* If it's a regular file */
3489 *q = NUL; /* keep just the path part */
3491 debug(F110,"ftp syncdir buf",buf,0);
3492 if (!strcmp(buf,putpath)) { /* Same path as previous file? */
3493 if (itsadir) { /* This file is a directory? */
3494 if (doftpcwd(local,0)) { /* Try to CD to it */
3495 doftpcdup(); /* Worked - CD back up */
3496 } else if (sim) { /* Simulating... */
3497 if (fdispla == XYFD_B) {
3498 printf("WOULD CREATE DIRECTORY %s\n",local);
3499 } else if (fdispla) {
3500 ckmakmsg(msgbuf,CKMAXPATH,
3501 "WOULD CREATE DIRECTORY",local,NULL,NULL);
3502 ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,msgbuf);
3504 /* See note above */
3506 } else if (!doftpxmkd(local,0)) { /* Can't CD - try to create */
3508 } else { /* Remote directory created OK */
3509 if (fdispla == XYFD_B) {
3510 printf("CREATED DIRECTORY %s\n",local);
3511 } else if (fdispla) {
3512 ckmakmsg(msgbuf,CKMAXPATH+64,
3513 "CREATED DIRECTORY ",local,NULL,NULL);
3514 ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,msgbuf);
3518 debug(F110,"ftp syncdir no change",buf,0);
3519 return(1); /* Yes, done. */
3521 ckstrncpy(tmp,buf,CKMAXPATH+1); /* Make a safe (pre-poked) copy */
3522 debug(F110,"ftp syncdir new path",buf,0); /* for later (see end) */
3525 s = putpath; /* Old */
3527 debug(F110,"ftp syncdir A (old) s",s,0); /* Previous */
3528 debug(F110,"ftp syncdir A (new) p",p,0); /* New */
3532 while (*p != NUL && *s != NUL && *p == *s) {
3533 if (*p == '/') { psep = p+1; ssep = s+1; }
3537 psep and ssep point to the first path segment that differs.
3538 We have to do as many CDUPs as there are path segments in ssep.
3539 then we have to do as many MKDs and CWDs as there are segments in psep.
3544 debug(F110,"ftp syncdir B (old) s",s,0); /* Previous */
3545 debug(F110,"ftp syncdir B (new) p",p,0); /* New */
3547 /* p and s now point to the leftmost spot where the paths differ */
3549 if (*s) { /* We have to back up */
3550 k = 1; /* How many levels counting this one */
3551 while ((c = *s++)) { /* Count dirseps remaining in prev */
3555 debug(F101,"ftp syncdir levels up","",k);
3557 for (i = 1; i <= k; i++) { /* Do that many CDUPs */
3558 debug(F111,"ftp syncdir CDUP A",p,i);
3559 if (fdispla == XYFD_B)
3561 if (sim && cdsimlvl) {
3571 if (!*p) /* If we don't have to go down */
3572 goto xcwd; /* we're done. */
3575 while (p > buf && *p && *p != '/') /* If in middle of segment */
3576 p--; /* back up to beginning */
3577 if (*p == '/') /* and terminate there */
3579 #endif /* COMMENT */
3581 debug(F110,"ftp syncdir NEW PATH",p,0);
3583 s = p; /* Point to start of new down path. */
3584 while (1) { /* Loop through characters. */
3585 if (*s == '/' || !*s) { /* Have a segment. */
3586 if (!*s) /* If end of string, */
3587 done++; /* after this segment we're done. */
3589 *s = NUL; /* NUL out the separator. */
3590 if (*p) { /* If segment is not empty */
3591 debug(F110,"ftp syncdir down segment",p,0);
3592 if (!doftpcwd(p,0)) { /* Try to CD to it */
3594 if (fdispla == XYFD_B) {
3595 printf(" WOULD CREATE DIRECTORY %s\n",local);
3596 } else if (fdispla) {
3597 ckmakmsg(msgbuf,CKMAXPATH,
3598 "WOULD CREATE DIRECTORY",
3600 ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,msgbuf);
3604 if (!doftpxmkd(p,0)) { /* Can't CD - try to create */
3605 debug(F110,"ftp syncdir mkdir failed",p,0);
3607 Suppose we are executing SEND /RECURSIVE. Locally we have a directory
3608 FOO but the remote has a regular file with the same name. We can't CD
3609 to it, can't MKDIR it either. There's no way out but to fail and let
3610 the user handle the problem.
3615 debug(F110,"ftp syncdir mkdir OK",p,0);
3616 if (fdispla == XYFD_B) {
3617 printf(" CREATED DIRECTORY %s\n",p);
3618 } else if (fdispla) {
3619 ckmakmsg(msgbuf,CKMAXPATH,
3620 "CREATED DIRECTORY ",p,NULL,NULL);
3621 ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,msgbuf);
3623 if (!doftpcwd(p,0)) { /* Try again to CD */
3624 debug(F110,"ftp syncdir CD failed",p,0);
3628 if (fdispla == XYFD_B) printf(" CWD %s\n",p);
3629 debug(F110,"ftp syncdir CD OK",p,0);
3634 if (done) /* Quit if no next segment */
3636 p = s+1; /* Point to next segment */
3638 s++; /* Point to next source char */
3642 ckstrncpy(putpath,tmp,CKMAXPATH+1); /* All OK - make this the new path */
3650 dbtime(s,xx) char * s; struct tm * xx; { /* Write struct tm to debug log */
3652 debug(F111,"ftp year ",s,xx->tm_year);
3653 debug(F111,"ftp month",s,xx->tm_mon);
3654 debug(F111,"ftp day ",s,xx->tm_mday);
3655 debug(F111,"ftp hour ",s,xx->tm_hour);
3656 debug(F111,"ftp min ",s,xx->tm_min);
3657 debug(F111,"ftp sec ",s,xx->tm_sec);
3662 /* t m c o m p a r e -- Compare two struct tm's */
3664 /* Like strcmp() but for struct tm's */
3665 /* Returns -1 if xx < yy, 0 if they are equal, 1 if xx > yy */
3668 tmcompare(xx,yy) struct tm * xx, * yy; {
3670 if (xx->tm_year < yy->tm_year) /* First year less than second */
3672 if (xx->tm_year > yy->tm_year) /* First year greater than second */
3675 /* Years are equal so compare months */
3677 if (xx->tm_mon < yy->tm_mon) /* And so on... */
3679 if (xx->tm_mon > yy->tm_mon)
3682 if (xx->tm_mday < yy->tm_mday)
3684 if (xx->tm_mday > yy->tm_mday)
3687 if (xx->tm_hour < yy->tm_hour)
3689 if (xx->tm_hour > yy->tm_hour)
3692 if (xx->tm_min < yy->tm_min)
3694 if (xx->tm_min > yy->tm_min)
3697 if (xx->tm_sec < yy->tm_sec)
3699 if (xx->tm_sec > yy->tm_sec)
3704 #endif /* DOUPDATE */
3706 #ifndef HAVE_TIMEGM /* For platforms that do not have timegm() */
3707 static CONST int MONTHDAYS[] = { /* Number of days in each month. */
3708 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
3711 /* Macro for whether a given year is a leap year. */
3712 #define ISLEAP(year) \
3713 (((year) % 4) == 0 && (((year) % 100) != 0 || ((year) % 400) == 0))
3714 #endif /* HAVE_TIMEGM */
3716 /* m k u t i m e -- Like mktime() but argument is already UTC */
3720 mkutime(struct tm * tm)
3722 mkutime(tm) struct tm * tm;
3723 #endif /* CK_ANSIC */
3726 return(timegm(tm)); /* Have system service, use it. */
3729 Contributed by Russ Allbery (rra@stanford.edu), used by permission.
3730 Given a struct tm representing a calendar time in UTC, convert it to
3731 seconds since epoch. Returns (time_t) -1 if the time is not
3732 convertable. Note that this function does not canonicalize the provided
3733 struct tm, nor does it allow out-of-range values or years before 1970.
3734 Result should be identical with timegm().
3739 We do allow some ill-formed dates, but we don't do anything special
3740 with them and our callers really shouldn't pass them to us. Do
3741 explicitly disallow the ones that would cause invalid array accesses
3742 or other algorithm problems.
3746 debug(F101,"mkutime tm_mon","",tm->tm_mon);
3747 debug(F101,"mkutime tm_year","",tm->tm_year);
3750 if (tm->tm_mon < 0 || tm->tm_mon > 11 || tm->tm_year < 70)
3751 return((time_t) -1);
3753 /* Convert to time_t. */
3754 for (i = 1970; i < tm->tm_year + 1900; i++)
3755 result += 365 + ISLEAP(i);
3756 for (i = 0; i < tm->tm_mon; i++)
3757 result += MONTHDAYS[i];
3758 if (tm->tm_mon > 1 && ISLEAP(tm->tm_year + 1900))
3760 result = 24 * (result + tm->tm_mday - 1) + tm->tm_hour;
3761 result = 60 * result + tm->tm_min;
3762 result = 60 * result + tm->tm_sec;
3763 debug(F101,"mkutime result","",result);
3765 #endif /* HAVE_TIMEGM */
3770 s e t m o d t i m e -- Set file modification time.
3772 f = char * filename;
3773 t = time_t date/time to set (Secs since 19700101 0:00:00 UTC, NOT local)
3775 UNIX-specific; isolates mainline code from hideous #ifdefs.
3783 setmodtime(char * f, time_t t)
3785 setmodtime(f,t) char * f; time_t t;
3786 #endif /* CK_ANSIC */
3795 struct timeval tp[2];
3796 #else /* def BSD44 */
3808 #else /* def SYSUTIMEH */
3811 #define SYSUTIMEH /* Our utimbuf matches this one. */
3817 #endif /* def VMS [else] */
3818 #endif /* def SYSUTIMEH [else] */
3819 #endif /* def V7 [else] */
3820 #endif /* def BSD44 [else] */
3822 if (stat(f,&sb) < 0) {
3823 debug(F111,"setmodtime stat failure",f,errno);
3827 tp[0].tv_sec = sb.st_atime; /* Access time first */
3828 tp[1].tv_sec = t; /* Update time second */
3829 debug(F111,"setmodtime BSD44",f,t);
3832 tp.timep[0] = t; /* Set modif. time to creation date */
3833 tp.timep[1] = sb.st_atime; /* Don't change the access time */
3834 debug(F111,"setmodtime V7",f,t);
3837 tp.modtime = t; /* Set modif. time to creation date */
3838 tp.actime = sb.st_atime; /* Don't change the access time */
3839 debug(F111,"setmodtime SYSUTIMEH",f,t);
3841 tp.mtime = t; /* Set modif. time to creation date */
3842 tp.atime = sb.st_atime; /* Don't change the access time */
3843 debug(F111,"setmodtime (other)",f,t);
3844 #endif /* SYSUTIMEH */
3848 /* Try to set the file date */
3852 debug(F111,"setmodtime utimes()","BSD44",x);
3857 The following produces the nonsensical warning:
3858 Argument of type "const struct utimbuf *" is incompatible with
3859 parameter of type "const struct utimbuf *". If you can make it
3860 go away, be my guest.
3862 const struct utimbuf * t2 = &tp;
3867 debug(F111,"setmodtime utime()","other",x);
3873 debug(F101,"setmodtime result","",rc);
3879 c h k m o d t i m e -- Check/Set file modification time.
3884 0 if local older than remote,
3885 1 if modtimes are equal,
3886 2 if local newer than remote.
3887 1 = Set (local file's modtime from remote's); returns:
3892 chkmodtime(local,remote,fc) char * local, * remote; int fc; {
3894 struct _stat statbuf;
3896 struct stat statbuf;
3898 struct tm * tmlocal = NULL;
3900 int rc = 0, havedate = 0, lcs = -1, rcs = -1, flag = 0;
3901 char * s, timebuf[64];
3903 debug(F111,"chkmodtime",local,mdtmok);
3904 if (!mdtmok) /* Server supports MDTM? */
3905 return(-1); /* No don't bother. */
3910 if (lcs < 0) lcs = fcharset;
3912 if (rcs < 0) rcs = ftp_csr;
3914 #endif /* NOCSETS */
3917 rc = stat(local,&statbuf);
3918 if (rc == 0) { /* Get local file's mod time */
3919 /* Convert to struct tm */
3920 tmlocal = gmtime((time_t *)&statbuf.st_mtime);
3923 dbtime(local,tmlocal);
3928 /* Get remote file's mod time as yyyymmddhhmmss */
3930 if (havemdtm) { /* Already got it from MLSD? */
3933 } else if (ftpcmd("MDTM",remote,lcs,rcs,0) == REPLY_COMPLETE) {
3935 bzero((char *)&tmremote, sizeof(struct tm));
3937 while ((c = *s++)) { /* Skip past response code */
3945 debug(F111,"ftp chkmodtime string",s,flag);
3946 if (fts_sto) { /* User gave server time offset? */
3948 debug(F110,"ftp chkmodtime offset",fts_sto,0);
3949 ckmakmsg(timebuf,64,s," ",fts_sto,NULL); /* Build delta time */
3950 if ((p = cmcvtdate(timebuf,1))) { /* Apply delta time */
3951 ckstrncpy(timebuf,p,64); /* Convert to MDTM format */
3952 timebuf[8] = timebuf[9]; /* h */
3953 timebuf[9] = timebuf[10]; /* h */
3954 timebuf[10] = timebuf[12]; /* m */
3955 timebuf[11] = timebuf[13]; /* m */
3956 timebuf[12] = timebuf[12]; /* s */
3957 timebuf[13] = timebuf[13]; /* s */
3960 debug(F110,"ftp chkmodtime adjust",s,0);
3963 if (flag) { /* Convert to struct tm */
3965 int y2kbug = 0; /* Seen in Kerberos 4 FTP servers */
3966 if (!ckstrcmp(s,"191",3,0)) {
3967 pat = "%05d%02d%02d%02d%02d%02d";
3969 debug(F110,"ftp chkmodtime Y2K BUG detected",s,0);
3971 pat = "%04d%02d%02d%02d%02d%02d";
3973 if (sscanf(s, /* Parse into struct tm */
3975 &(tmremote.tm_year),
3977 &(tmremote.tm_mday),
3978 &(tmremote.tm_hour),
3982 tmremote.tm_year -= (y2kbug ? 19000 : 1900);
3983 debug(F101,"ftp chkmodtime year","",tmremote.tm_year);
3987 debug(F100,"SERVER TIME FOLLOWS:","",0);
3988 dbtime(remote,&tmremote);
3995 } else { /* Failed */
3996 debug(F101,"ftp chkmodtime ftpcode","",ftpcode);
3997 if (ftpcode == 500 || /* Command unrecognized */
3998 ftpcode == 502 || /* Command not implemented */
3999 ftpcode == 202) /* Command superfluous */
4000 mdtmok = 0; /* Don't ask this server again */
4003 if (fc == 0) { /* Compare */
4004 if (havedate == 1) { /* Only if we have both file dates */
4006 Compare with local file's time. We don't use
4007 clock time (time_t) here in case of signed/unsigned
4014 dbtime("LOCAL",tmlocal);
4015 dbtime("REMOT",&tmremote);
4018 #endif /* COMMENT */
4019 xx = tmcompare(tmlocal,&tmremote);
4020 debug(F101,"chkmodtime tmcompare","",xx);
4023 } else if (ftp_dates) { /* Set */
4025 Here we must convert struct tm to time_t
4026 without applying timezone conversion, for which
4027 there is no portable API. The method is hidden
4028 in mkutime(), defined above.
4031 utc = mkutime(&tmremote);
4032 debug(F111,"ftp chkmodtime mkutime",remote,utc);
4033 if (utc != (time_t)-1)
4034 return(setmodtime(local,utc));
4039 /* getfile() returns: -1 on error, 0 if file received, 1 if file skipped */
4042 getfile(remote,local,recover,append,pipename,xlate,fcs,rcs)
4043 char * local, * remote, * pipename; int recover, append, xlate, fcs, rcs;
4052 #endif /* GFTIMER */
4053 char fullname[CKMAXPATH+1];
4055 debug(F110,"ftp getfile remote A",remote,0);
4056 debug(F110,"ftp getfile local A",local,0);
4057 debug(F110,"ftp getfile pipename",pipename,0);
4058 if (!remote) remote = "";
4061 /* Automatic type switching? */
4062 if (ftp_xfermode == XMODE_A && patterns && get_auto && !forcetype) {
4064 x = matchname(remote,0,servertype);
4065 debug(F111,"ftp getfile matchname",remote,x);
4067 case 0: ftp_typ = FTT_ASC; break;
4068 case 1: ftp_typ = tenex ? FTT_TEN : FTT_BIN; break;
4069 default: if (g_ftp_typ > -1) ftp_typ = g_ftp_typ;
4071 changetype(ftp_typ,ftp_vbm);
4072 binary = ftp_typ; /* For file-transfer display */
4074 #endif /* PATTERNS */
4077 ftp_csx = -1; /* For file-transfer display */
4078 ftp_csl = -1; /* ... */
4080 if (rcs > -1) /* -1 means no translation */
4081 if (ftp_typ == FTT_ASC) /* File type is "ascii"? */
4082 if (fcs < 0) /* File charset not forced? */
4083 fcs = fcharset; /* use prevailing FILE CHARACTER-SET */
4084 if (fcs > -1 && rcs > -1) { /* Set up translation functions */
4085 debug(F110,"ftp getfile","initxlate",0);
4086 initxlate(rcs,fcs); /* NB: opposite order of PUT */
4091 #endif /* NOCSETS */
4093 if (!local) local = "";
4094 if (!pipename && !*local)
4097 out2screen = !strcmp(local,"-");
4101 ckstrncpy(fullname,pipename,CKMAXPATH+1);
4103 zfnqfp(local,CKMAXPATH,fullname);
4105 ckstrncpy(fullname,local,CKMAXPATH+1);
4107 if (!out2screen && displa && fdispla) { /* Screen */
4108 ftscreen(SCR_FN,'F',(CK_OFF_T)pktnum,remote);
4109 ftscreen(SCR_AN,0,(CK_OFF_T)0,fullname);
4110 ftscreen(SCR_FS,0,fsize,"");
4112 tlog(F110,ftp_typ ? "ftp get BINARY:" : "ftp get TEXT:", remote, 0);
4113 tlog(F110," as",fullname,0);
4114 debug(F111,"ftp getfile size",remote,fsize);
4115 debug(F111,"ftp getfile local",local,out2screen);
4117 ckstrncpy(filnam, pipename ? remote : local, CKMAXPATH);
4119 t0 = gmstimer(); /* Start time */
4120 debug(F111,"ftp getfile t0",remote,t0); /* ^^^ */
4121 rc = recvrequest("RETR",
4124 append ? "ab" : "wb",
4132 t1 = gmstimer(); /* End time */
4133 debug(F111,"ftp getfile t1",remote,t1);
4134 debug(F111,"ftp getfile sec",remote,(t1-t0)/1000);
4136 sec = (CKFLOAT)((CKFLOAT)(t1 - t0) / 1000.0); /* Stats */
4137 fpxfsecs = sec; /* (for doxlog()) */
4139 sec = (t1 - t0) / 1000;
4141 #endif /* GFTIMER */
4146 #endif /* FTP_TIMEOUT */
4148 debug(F111,"ftp recvrequest rc",remote,rc);
4149 if (cancelfile || cancelgroup) {
4150 debug(F111,"ftp get canceled",ckitoa(cancelfile),cancelgroup);
4151 ftscreen(SCR_ST,ST_INT,(CK_OFF_T)0,"");
4152 } else if (rc > 0) {
4153 debug(F111,"ftp get skipped",ckitoa(cancelfile),cancelgroup);
4154 ftscreen(SCR_ST,ST_SKIP,(CK_OFF_T)0,cmarg);
4155 } else if (rc < 0) {
4157 case -4: /* Network error */
4158 case -2: /* File error */
4159 ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,ck_errstr());
4162 ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,
4163 "Failure to make data connection");
4165 case -1: /* (should be covered above) */
4166 ftscreen(SCR_ST,ST_INT,(CK_OFF_T)0,"");
4169 ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,&ftp_reply_str[4]);
4171 } else { /* Tudo bem */
4172 ftscreen(SCR_PT,'Z',(CK_OFF_T)0,"");
4174 ftscreen(SCR_ST,ST_OK,(CK_OFF_T)0,""); /* For screen */
4175 makestr(&rrfspec,remote); /* For WHERE command */
4176 makestr(&rfspec,fullname);
4180 if (ftp_dates) /* If FTP DATES ON... */
4181 if (!pipename && !out2screen) /* and it's a real file */
4182 if (rc < 1 && rc != -3) /* and it wasn't skipped */
4183 if (connected) /* and we still have a connection */
4184 if (zchki(local) > -1) { /* and the file wasn't discarded */
4185 chkmodtime(local,remote,1); /* set local file date */
4186 debug(F110,"ftp get set date",local,0);
4188 filcnt++; /* Used by \v(filenum) */
4193 tlog(F100," recovery skipped","",0);
4194 } else if (rc == 0) {
4195 tlog(F101," complete, size", "", fsize);
4196 } else if (cancelfile) {
4197 tlog(F100," canceled by user","",0);
4199 } else if (ftp_timed_out) {
4200 tlog(F100," timed out","",0);
4201 #endif /* FTP_TIMEOUT */
4203 tlog(F110," failed:",ftp_reply_str,0);
4206 doxlog(what,local,fsize,ftp_typ,rc,"");
4212 /* putfile() returns: -1 on error, >0 if file not selected, 0 on success. */
4213 /* Positive return value is Skip Reason, SKP_xxx, from ckcker.h. */
4217 local,remote,force,moving,mvto,rnto,srvrn,x_cnv,x_usn,xft,prm,fcs,rcs,flg)
4218 char * local, * remote, * mvto, *rnto, *srvrn;
4219 int cx, force, moving, x_cnv, x_usn, xft, fcs, rcs, flg, prm;
4223 char asname[CKMAXPATH+1];
4224 char fullname[CKMAXPATH+1];
4225 int k = -1, x = 0, y = 0, o = -1, rc = 0, nc = 0;
4226 int xlate = 0, restart = 0, mt = -1;
4227 char * s = NULL, * cmd = NULL;
4228 ULONG t0 = 0, t1 = 0; /* Times for stats */
4229 int ofcs = 0, orcs = 0;
4235 #endif /* GFTIMER */
4236 debug(F111,"ftp putfile flg",local,flg);
4237 debug(F110,"ftp putfile srv_renam",srvrn,0);
4238 debug(F101,"ftp putfile fcs","",fcs);
4239 debug(F101,"ftp putfile rcs","",rcs);
4241 ofcs = fcs; /* Save charset args */
4244 sendstart = (CK_OFF_T)0;
4245 restart = flg & PUT_RES;
4249 /* FTP protocol command to send to server */
4250 cmd = (cx == FTP_APP) ? "APPE" : (x_usn ? "STOU" : "STOR");
4252 if (x_cnv == SET_AUTO) { /* Name conversion is auto */
4253 if (alike) { /* If server & client are alike */
4254 nc = 0; /* no conversion */
4255 } else { /* If they are different */
4256 if (servertype == SYS_UNIX || servertype == SYS_WIN32)
4257 nc = -1; /* only minimal conversions needed */
4258 else /* otherwise */
4259 nc = 1; /* full conversion */
4261 } else /* Not auto - do what user said */
4264 /* If Transfer Mode is Automatic, determine file type */
4265 if (ftp_xfermode == XMODE_A && filepeek && !pipesend) {
4266 if (isdir(local)) { /* If it's a directory */
4267 k = FT_BIN; /* skip the file scan */
4269 debug(F110,"FTP PUT calling scanfile",local,0);
4270 k = scanfile(local,&o,nscanfile); /* Scan the file */
4272 debug(F111,"FTP PUT scanfile",local,k);
4273 if (k > -1 && !forcetype) {
4274 ftp_typ = (k == FT_BIN) ? 1 : 0;
4275 if (xft > -1 && ftp_typ != xft) {
4277 tlog(F110,"ftp put SKIP (Type):", local, 0);
4280 if (ftp_typ == 1 && tenex) /* User said TENEX? */
4285 ftp_csx = -1; /* For file-transfer display */
4286 ftp_csl = -1; /* ... */
4288 if (rcs > -1) { /* -1 means no translation */
4289 if (ftp_typ == 0) { /* File type is "ascii"? */
4290 if (fcs < 0) { /* File charset not forced? */
4291 if (k < 0) { /* If we didn't scan */
4292 fcs = fcharset; /* use prevailing FILE CHARACTER-SET */
4293 } else { /* If we did scan, use scan result */
4295 case FT_TEXT: /* Unknown text */
4298 case FT_7BIT: /* 7-bit text */
4301 case FT_8BIT: /* 8-bit text */
4304 case FT_UTF8: /* UTF-8 */
4307 case FT_UCS2: /* UCS-2 */
4309 if (o > -1) /* Input file byte order */
4319 if (fcs > -1 && rcs > -1) { /* Set up translation functions */
4320 debug(F110,"ftp putfile","initxlate",0);
4322 debug(F111,"ftp putfile rcs",fcsinfo[rcs].keyword,rcs);
4327 #endif /* NOCSETS */
4329 binary = ftp_typ; /* For file-transfer display */
4332 if (recursive) { /* If sending recursively, */
4333 if (!syncdir(local,flg & PUT_SIM)) /* synchronize directories. */
4334 return(-1); /* Don't PUT if it fails. */
4335 else if (isdir(local)) /* It's a directory */
4336 return(0); /* Don't send it! */
4338 if (*remote) { /* If an as-name template was given */
4340 if (cmd_quoting) { /* and COMMAND QUOTING is ON */
4341 y = CKMAXPATH; /* evaluate it for this file */
4343 zzstring(remote,&s,&y);
4346 ckstrncpy(asname,remote,CKMAXPATH); /* (or take it literally) */
4347 } else { /* No as-name */
4348 nzltor(local,asname,nc,0,CKMAXPATH); /* use local name strip path */
4349 debug(F110,"FTP PUT nzltor",asname,0);
4351 /* Preliminary messages and log entries */
4354 zfnqfp(local,CKMAXPATH,fullname);
4355 if (!fullname[0]) ckstrncpy(fullname,local,CKMAXPATH+1);
4356 fullname[CKMAXPATH] = NUL;
4358 if (displa && fdispla) { /* Screen */
4359 ftscreen(SCR_FN,'F',(CK_OFF_T)pktnum,local);
4360 ftscreen(SCR_AN,0,(CK_OFF_T)0,asname);
4361 ftscreen(SCR_FS,0,fsize,"");
4364 if (flg & (PUT_UPD|PUT_DIF)) { /* Date-checking modes... */
4365 mt = chkmodtime(fullname,asname,0);
4366 debug(F111,"ftp putfile chkmodtime",asname,mt);
4367 if (mt == 0 && ((flg & PUT_DIF) == 0)) { /* Local is older */
4368 tlog(F110,"ftp put /update SKIP (Older modtime): ",fullname,0);
4370 ftscreen(SCR_ST,ST_SKIP,(CK_OFF_T)SKP_DAT,fullname);
4373 } else if (mt == 1) { /* Times are equal */
4374 tlog(F110,"ftp put /update SKIP (Equal modtime): ",fullname,0);
4375 ftscreen(SCR_ST,ST_SKIP,(CK_OFF_T)SKP_EQU,fullname); /* Skip it */
4379 /* Local file is newer */
4380 tlog(F110,ftp_typ ? "ftp put /update BINARY:" :
4381 "ftp put /update TEXT:", fullname, 0);
4382 } else if (flg & PUT_RES) {
4383 tlog(F110,ftp_typ ? "ftp put /recover BINARY:" :
4384 "ftp put /recover TEXT:", fullname, 0);
4386 tlog(F110,ftp_typ ? "ftp put BINARY:" : "ftp put TEXT:", fullname, 0);
4389 tlog(F110,ftp_typ ? "ftp put BINARY:" : "ftp put TEXT:", fullname, 0);
4390 #endif /* DOUPDATE */
4391 tlog(F110," as",asname,0);
4395 debug(F111,"ftp putfile fcs",fcsinfo[fcs].keyword,fcs);
4396 tlog(F110," file character set:",fcsinfo[fcs].keyword,0);
4397 tlog(F110," server character set:",fcsinfo[rcs].keyword,0);
4398 } else if (!ftp_typ) {
4399 tlog(F110," character sets:","no conversion",0);
4400 fcs = ofcs; /* Binary file but we still must */
4401 rcs = orcs; /* translate its name */
4403 #endif /* NOCSETS */
4407 t0 = gmstimer(); /* Start time */
4408 if (flg & PUT_SIM) { /* rc > 0 is a skip reason code */
4409 if (flg & (PUT_UPD|PUT_DIF)) { /* (see SKP_xxx in ckcker.h) */
4410 rc = (mt < 0) ? /* Update mode... */
4411 SKP_XNX : /* Remote file doesn't exist */
4412 SKP_XUP; /* Remote file is older */
4414 rc = SKP_SIM; /* "Would be sent", period. */
4417 rc = sendrequest(cmd,local,asname,xlate,fcs,rcs,restart);
4419 t1 = gmstimer(); /* End time */
4420 filcnt++; /* File number */
4423 sec = (CKFLOAT)((CKFLOAT)(t1 - t0) / 1000.0); /* Stats */
4424 fpxfsecs = sec; /* (for doxlog()) */
4426 sec = (t1 - t0) / 1000;
4428 #endif /* GFTIMER */
4430 debug(F111,"ftp sendrequest rc",local,rc);
4432 if (cancelfile || cancelgroup) {
4433 debug(F111,"ftp put canceled",ckitoa(cancelfile),cancelgroup);
4434 ftscreen(SCR_ST,ST_INT,(CK_OFF_T)0,"");
4435 } else if (rc > 0) {
4436 debug(F101,"ftp put skipped",local,rc);
4437 ftscreen(SCR_ST,ST_SKIP,(CK_OFF_T)rc,fullname);
4438 } else if (rc < 0) {
4439 debug(F111,"ftp put error",local,ftpcode);
4440 ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,&ftp_reply_str[4]);
4442 debug(F111,"ftp put not canceled",ckitoa(displa),fdispla);
4443 ftscreen(SCR_PT,'Z',(CK_OFF_T)0,"");
4444 debug(F111,"ftp put ST_OK",local,rc);
4445 ftscreen(SCR_ST,ST_OK,(CK_OFF_T)0,"");
4446 debug(F110,"ftp put old sfspec",sfspec,0);
4447 makestr(&sfspec,fullname); /* For WHERE command */
4448 debug(F110,"ftp put new sfspec",sfspec,0);
4449 debug(F110,"ftp put old srfspec",srfspec,0);
4450 makestr(&srfspec,asname);
4451 debug(F110,"ftp put new srfspec",srfspec,0);
4454 /* Final log entries */
4460 tlog(F100," /simulate: WOULD BE SENT:","no remote file",0);
4461 else if (rc == SKP_XUP)
4462 tlog(F100," /simulate: WOULD BE SENT:","remote file older",0);
4463 else if (rc == SKP_SIM)
4464 tlog(F100," /simulate: WOULD BE SENT","",0);
4466 tlog(F110," skipped:",gskreason(rc),0);
4467 } else if (rc == 0) {
4468 tlog(F101," complete, size", "", fsize);
4469 } else if (cancelfile) {
4470 tlog(F100," canceled by user","",0);
4472 tlog(F110," failed:",ftp_reply_str,0);
4475 doxlog(what,local,fsize,ftp_typ,rc,"");
4479 if (rc < 0) /* PUT did not succeed */
4480 return(-1); /* so done. */
4482 if (flg & PUT_SIM) /* Simulating, skip the rest. */
4486 /* Set permissions too? */
4488 if (prm) { /* Change permissions? */
4489 s = zgperm(local); /* Get perms of local file */
4492 if (x > 3) s += (x - 3);
4494 ckmakmsg(ftpcmdbuf,FTP_BUFSIZ,s," ",asname,NULL);
4496 ftpcmd("SITE CHMOD",ftpcmdbuf,fcs,rcs,ftp_vbm) == REPLY_COMPLETE;
4497 tlog(F110, x ? " chmod" : " chmod failed",
4507 /* Disposition of source file */
4511 tlog(F110, (x > -1) ?
4512 " deleted" : " failed to delete",
4519 x = zrename(local,mvto);
4520 tlog(F110, (x > -1) ?
4521 " moved source to" : " failed to move source to",
4527 /* ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,mvto); */
4532 int y; /* Pass it thru the evaluator */
4533 extern int cmd_quoting; /* for \v(filename) */
4534 if (cmd_quoting) { /* But only if cmd_quoting is on */
4537 zzstring(rnto,&s,&y);
4543 x = zrename(local,s);
4544 tlog(F110, (x > -1) ?
4545 " renamed source file to" :
4546 " failed to rename source file to",
4552 /* ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,s); */
4556 /* Disposition of destination file */
4558 if (srvrn) { /* /SERVER-RENAME: */
4561 int y; /* Pass it thru the evaluator */
4562 extern int cmd_quoting; /* for \v(filename) */
4563 debug(F111,"ftp putfile srvrn",s,1);
4565 if (cmd_quoting) { /* But only if cmd_quoting is on */
4567 s = (char *)fullname; /* We can recycle this buffer now */
4568 zzstring(srvrn,&s,&y);
4569 s = (char *)fullname;
4572 debug(F111,"ftp putfile srvrn",s,2);
4575 x = ftp_rename(asname,s);
4576 debug(F111,"ftp putfile ftp_rename",asname,x);
4577 tlog(F110, (x > 0) ?
4578 " renamed destination file to" :
4579 " failed to rename destination file to",
4590 /* xxout must only be used for ASCII transfers */
4596 #endif /* CK_ANSIC */
4602 /* For Unix, DG, Stratus, Amiga, Gemdos, other */
4604 if (zzout(dout,(CHAR)'\015') < 0)
4611 if (zzout(dout,(CHAR)'\015') < 0)
4619 if (zzout(dout,(CHAR)'\015') < 0)
4626 if (zzout(dout,(CHAR)c) < 0)
4637 #endif /* CK_ANSIC */
4647 #endif /* CK_ANSIC */
4653 ispathsep(c) int c; {
4654 switch (servertype) {
4658 return(((c == ']') || (c == '>') || (c == ':')) ? 1 : 0);
4662 return(((c == '\\') || (c == '/') || (c == ':')) ? 1 : 0);
4664 return((c == '>') ? 1 : 0);
4666 return((c == '/') ? 1 : 0);
4673 extern int ck_repaint();
4674 #endif /* CK_CURSES */
4679 x = conchk(); /* Any chars waiting at console? */
4680 if (x-- > 0) { /* Yes... */
4681 c = coninc(5); /* Get one */
4683 case 032: /* Ctrl-X or X */
4685 case 'Z': cancelgroup++; /* fall thru on purpose */
4686 case 030: /* Ctrl-Z or Z */
4688 case 'X': cancelfile++; rc++; break;
4692 case 014: /* Ctrl-L or L or Ctrl-W */
4694 ck_repaint(); /* Refresh screen */
4695 #endif /* CK_CURSES */
4698 while (x-- > 0) /* Soak up any rest */
4704 /* fc = 0 for read; 1 for write */
4706 check_data_connection(fd,fc) int fd, fc; {
4709 fd_set in, out, err;
4711 if (ftp_timeout < 1L)
4717 FD_SET(fd,fc ? &out : &in);
4718 tv.tv_sec = ftp_timeout; /* Time limit */
4722 x = select(FD_SETSIZE,(int *)&in,(int *)&out,(int *)&err,&tv);
4724 x = select(FD_SETSIZE,&in,&out,&err,&tv);
4725 #endif /* INTSELECT */
4729 errno = EWOULDBLOCK;
4736 #endif /* EWOULDBLOCK */
4737 debug(F100,"ftp check_data_connection TIMOUT","",0);
4742 #endif /* FTP_TIMEOUT */
4744 /* zzsend - used by buffered output macros. */
4748 zzsend(int fd, CHAR c)
4750 zzsend(fd,c) int fd; CHAR c;
4751 #endif /* CK_ANSIC */
4755 debug(F101,"zzsend ucbufsiz","",ucbufsiz);
4756 debug(F101,"zzsend nout","",nout);
4757 debug(F111,"zzsend","secure?",ftpissecure());
4759 if (iscanceled()) /* Check for cancellation */
4764 if (check_data_connection(fd,1) < 0) {
4768 #endif /* FTP_TIMEOUT */
4770 rc = (!ftpissecure()) ?
4771 send(fd, (SENDARG2TYPE)ucbuf, nout, 0) :
4772 secure_putbuf(fd, ucbuf, nout);
4778 if (rc > -1 && fdispla != XYFD_B) {
4780 ftscreen(SCR_PT,'D',(CK_OFF_T)spackets,NULL);
4785 /* c m d l i n p u t -- Command-line PUT */
4788 cmdlinput(stay) int stay; {
4789 int x, rc = 0, done = 0, good = 0, status = 0;
4790 ULONG t0, t1; /* Times for stats */
4795 #endif /* GFTIMER */
4797 if (quiet) { /* -q really means quiet */
4807 what = W_FTP|W_SEND;
4814 t0 = gmstimer(); /* Record starting time */
4816 while (!done && !cancelgroup) { /* Loop for all files */
4819 x = gnfile(); /* Get next file from list(s) */
4820 if (x == 0) /* (see gnfile() comments...) */
4824 case 1: /* File to send */
4825 rc = putfile(FTP_PUT, /* Function (PUT, APPEND) */
4826 filnam, /* Local file to send */
4827 filnam, /* Remote name for file */
4828 forcetype, /* Text/binary mode forced */
4830 NULL, /* No move-to */
4831 NULL, /* No rename-to */
4832 NULL, /* No server-rename */
4833 ftp_cnv, /* Filename conversion */
4834 0, /* Unique-server-names */
4835 -1, /* All file types */
4836 0, /* No permissions */
4837 -1, /* No character sets */
4838 -1, /* No character sets */
4839 0 /* No update or restart */
4846 continue; /* Or break? */
4851 continue; /* Or break? */
4853 case 0: /* No more files, done */
4859 printf("?%s: file not found - \"%s\"\n",
4860 puterror ? "Fatal" : "Warning",
4863 continue; /* or break? */
4865 printf("?Warning access denied - \"%s\"\n", filnam);
4866 continue; /* or break? */
4868 printf("?Too many files match\n");
4873 printf("?No files selected\n");
4877 printf("?getnextfile() - unknown failure\n");
4884 else if (cancelfile && good < 1)
4890 lastxfer = W_FTP|W_SEND;
4893 t1 = gmstimer(); /* End time */
4895 sec = (CKFLOAT)((CKFLOAT)(t1 - t0) / 1000.0); /* Stats */
4896 if (!sec) sec = 0.001;
4899 sec = (t1 - t0) / 1000;
4901 #endif /* GFTIMER */
4902 tfcps = (long) (tfc / sec);
4904 lastxfer = W_FTP|W_SEND;
4907 ftscreen(status > 0 ? SCR_TC : SCR_CW, 0, (CK_OFF_T)0, "");
4909 doexit(success ? GOOD_EXIT : BAD_EXIT, -1);
4914 /* d o f t p p u t -- Parse and execute PUT, MPUT, and APPEND */
4918 doftpput(int cx, int who) /* who == 1 for ftp, 0 for kermit */
4920 doftpput(cx,who) int cx, who;
4921 #endif /* CK_ANSIC */
4923 struct FDB sf, fl, sw, cm;
4924 int n, rc, confirmed = 0, wild = 0, getval = 0, mput = 0, done = 0;
4925 int x_cnv = 0, x_usn = 0, x_prm = 0, putflags = 0, status = 0, good = 0;
4928 int x_csl, x_csr = -1; /* Local and remote charsets */
4931 char c, * p; /* Workers */
4933 int range[2]; /* Array range */
4934 char ** ap = NULL; /* Array pointer */
4935 int arrayx = -1; /* Array index */
4936 #endif /* PUTARRAY */
4937 ULONG t0 = 0L, t1 = 0L; /* Times for stats */
4942 #endif /* GFTIMER */
4944 struct stringint pv[SND_MAX+1]; /* Temporary array for switch values */
4945 success = 0; /* Assume failure */
4946 forcetype = 0; /* No /TEXT or /BINARY given yet */
4947 out2screen = 0; /* Not outputting file to screen */
4948 putflags = 0; /* PUT options */
4949 x_cnv = ftp_cnv; /* Filename conversion */
4950 x_usn = ftp_usn; /* Unique server names */
4951 x_prm = ftp_prm; /* Permissions */
4952 if (x_prm == SET_AUTO) /* Permissions AUTO */
4956 x_csr = ftp_csr; /* Inherit global server charset */
4961 #endif /* NOCSETS */
4963 makestr(&filefile,NULL); /* No filename list file yet. */
4964 makestr(&srv_renam,NULL); /* Clear /SERVER-RENAME: */
4965 makestr(&snd_rename,NULL); /* PUT /RENAME */
4966 makestr(&snd_move,NULL); /* PUT /MOVE */
4967 putpath[0] = NUL; /* Initialize for syncdir(). */
4968 puterror = ftp_err; /* Inherit global error action. */
4969 what = W_SEND|W_FTP; /* What we're doing (sending w/FTP) */
4970 asnambuf[0] = NUL; /* Clear as-name buffer */
4972 if (g_ftp_typ > -1) { /* Restore TYPE if saved */
4973 ftp_typ = g_ftp_typ;
4974 /* g_ftp_typ = -1; */
4976 for (i = 0; i <= SND_MAX; i++) { /* Initialize switch values */
4977 pv[i].sval = NULL; /* to null pointers */
4978 pv[i].ival = -1; /* and -1 int values */
4979 pv[i].wval = (CK_OFF_T)-1; /* and -1 wide values */
4981 if (who == 0) { /* Called with unprefixed command */
4983 case XXRSEN: pv[SND_RES].ival = 1; break;
4984 case XXCSEN: pv[SND_CMD].ival = 1; break;
4985 case XXMOVE: pv[SND_DEL].ival = 1; break;
4986 case XXMMOVE: pv[SND_DEL].ival = 1; /* fall thru */
4987 case XXMSE: mput++; break;
4991 pv[SND_RES].ival = 1;
4995 cmfdbi(&sw, /* First FDB - command switches */
4997 "Filename, or switch", /* hlpmsg */
4999 "", /* addtl string data */
5000 nputswi, /* addtl numeric data 1: tbl size */
5001 4, /* addtl numeric data 2: 4 = cmswi */
5002 xxstring, /* Processing function */
5003 putswi, /* Keyword table */
5004 &sf /* Pointer to next FDB */
5006 cmfdbi(&fl, /* 3rd FDB - local filespec */
5010 "", /* addtl string data */
5011 0, /* addtl numeric data 1 */
5012 0, /* addtl numeric data 2 */
5017 cmfdbi(&cm, /* 4th FDB - Confirmation */
5021 "", /* addtl string data */
5022 0, /* addtl numeric data 1 */
5023 0, /* addtl numeric data 2 */
5030 cmfdbi(&sf, /* 2nd FDB - file to send */
5034 "", /* addtl string data */
5035 /* 0 = parse files, 1 = parse files or dirs, 2 = skip symlinks */
5036 nolinks | x_recurse, /* addtl numeric data 1 */
5037 0, /* dirflg 0 means "not dirs only" */
5044 #endif /* COMMENT */
5047 while (1) { /* Parse zero or more switches */
5048 x = cmfdb(&sw); /* Parse something */
5049 debug(F101,"ftp put cmfdb A","",x);
5050 debug(F101,"ftp put fcode A","",cmresult.fcode);
5051 if (x < 0) /* Error */
5052 goto xputx; /* or reparse needed */
5053 if (cmresult.fcode != _CMKEY) /* Break out of loop if not a switch */
5055 c = cmgbrk(); /* Get break character */
5056 getval = (c == ':' || c == '='); /* to see how they ended the switch */
5057 if (getval && !(cmresult.kflags & CM_ARG)) {
5058 printf("?This switch does not take arguments\n");
5062 if (!getval && (cmgkwflgs() & CM_ARG)) {
5063 printf("?This switch requires an argument\n");
5067 n = cmresult.nresult; /* Numeric result = switch value */
5068 debug(F101,"ftp put switch","",n);
5070 switch (n) { /* Process the switch */
5071 case SND_AFT: /* Send /AFTER:date-time */
5072 case SND_BEF: /* Send /BEFORE:date-time */
5073 case SND_NAF: /* Send /NOT-AFTER:date-time */
5074 case SND_NBE: /* Send /NOT-BEFORE:date-time */
5076 if ((x = cmdate("File date-time","",&s,0,xxstring)) < 0) {
5078 printf("?Date-time required\n");
5084 makestr(&(pv[n].sval),s);
5087 case SND_ASN: /* /AS-NAME: */
5088 debug(F101,"ftp put /as-name getval","",getval);
5090 if ((x = cmfld("Name to send under","",&s,NULL)) < 0) {
5092 printf("?name required\n");
5097 makestr(&(pv[n].sval),brstrip(s));
5098 debug(F110,"ftp put /as-name 1",pv[n].sval,0);
5099 if (pv[n].sval) pv[n].ival = 1;
5103 case SND_ARR: /* /ARRAY */
5106 if ((x = cmfld("Array name (a single letter will do)",
5116 if ((x = arraybounds(s,&(range[0]),&(range[1]))) < 0) {
5117 printf("?Bad array: %s\n",s);
5120 if (!(ap = a_ptr[x])) {
5121 printf("?No such array: %s\n",s);
5125 pv[SND_CMD].ival = 0; /* Undo any conflicting ones... */
5126 pv[SND_RES].ival = 0;
5127 pv[SND_FIL].ival = 0;
5130 #endif /* PUTARRAY */
5132 case SND_BIN: /* /BINARY */
5133 case SND_TXT: /* /TEXT or /ASCII */
5134 case SND_TEN: /* /TENEX */
5135 pv[SND_BIN].ival = 0;
5136 pv[SND_TXT].ival = 0;
5137 pv[SND_TEN].ival = 0;
5142 case SND_CMD: /* These take no args */
5144 printf("?Sorry, system command access is disabled\n");
5149 else if (sndfilter) {
5150 printf("?Sorry, no PUT /COMMAND when SEND FILTER selected\n");
5154 #endif /* PIPESEND */
5155 sw.hlpmsg = "Command, or switch"; /* Change help message */
5156 pv[n].ival = 1; /* Just set the flag */
5157 pv[SND_ARR].ival = 0;
5159 #endif /* PUTPIPE */
5164 goto again; /* Because CMIFI params changed... */
5168 #endif /* CKSYMLINK */
5171 case SND_RES: /* /RECOVER (resend) */
5172 pv[SND_ARR].ival = 0; /* fall thru on purpose... */
5173 #endif /* FTP_RESTART */
5176 case SND_DEL: /* /DELETE */
5177 case SND_SHH: /* /QUIET */
5178 case SND_UPD: /* /UPDATE */
5179 case SND_SIM: /* /UPDATE */
5180 case SND_USN: /* /UNIQUE */
5181 pv[n].ival = 1; /* Just set the flag */
5184 case SND_REC: /* /RECURSIVE */
5185 recursive = 2; /* Must be set before cmifi() */
5187 goto again; /* Because CMIFI params changed... */
5191 case SND_DOT: /* /DOTFILES */
5194 case SND_NOD: /* /NODOTFILES */
5197 #endif /* UNIXOROSK */
5199 case SND_ERR: /* /ERROR-ACTION */
5200 if ((x = cmkey(qorp,2,"","",xxstring)) < 0)
5205 case SND_EXC: /* Excludes */
5207 if ((x = cmfld("Pattern","",&s,xxstring)) < 0) {
5209 printf("?Pattern required\n");
5214 if (s) if (!*s) s = NULL;
5215 makestr(&(pv[n].sval),s);
5220 case SND_PRM: /* /PERMISSIONS */
5223 else if ((x = cmkey(onoff,2,"","on",xxstring)) < 0)
5225 pv[SND_PRM].ival = x;
5229 case SND_FLT: /* /FILTER */
5230 debug(F101,"ftp put /filter getval","",getval);
5232 if ((x = cmfld("Filter program to send through","",&s,NULL)) < 0) {
5238 if (*s) s = brstrip(s);
5240 for (x = 0; x < y; x++) { /* Make sure they included "\v(...)" */
5241 if (s[x] != '\\') continue;
5242 if (s[x+1] == 'v') break;
5246 "?Filter must contain a replacement variable for filename.\n"
5251 if (s) if (!*s) s = NULL;
5252 makestr(&(pv[n].sval),s);
5256 #endif /* PIPESEND */
5258 case SND_NAM: /* /FILENAMES */
5260 if ((x = cmkey(fntab,nfntab,"","automatic",xxstring)) < 0)
5262 debug(F101,"ftp put /filenames","",x);
5266 case SND_SMA: /* Smaller / larger than */
5270 if ((x = cmnumw("Size in bytes","0",10,&y,xxstring)) < 0)
5275 case SND_FIL: /* Name of file containing filenames */
5277 if ((x = cmifi("Name of file containing list of filenames",
5278 "",&s,&y,xxstring)) < 0) {
5280 printf("?Filename required\n");
5284 } else if (y && iswild(s)) {
5285 printf("?Wildcards not allowed\n");
5289 if (s) if (!*s) s = NULL;
5290 makestr(&(pv[n].sval),s);
5293 pv[SND_ARR].ival = 0;
5300 case SND_MOV: /* MOVE after */
5301 case SND_REN: /* RENAME after */
5302 case SND_SRN: { /* SERVER-RENAME after */
5306 m = "device and/or directory for source file after sending";
5309 m = "new name for source file after sending";
5312 m = "new name for destination file after sending";
5316 if ((x = cmfld(m, "", &s, n == SND_MOV ? xxstring : NULL)) < 0) {
5318 printf("%s\n", n == SND_MOV ?
5319 "?Destination required" :
5320 "?New name required"
5326 if (s) if (!*s) s = NULL;
5327 makestr(&(pv[n].sval),s ? brstrip(s) : NULL);
5328 pv[n].ival = (pv[n].sval) ? 1 : 0;
5331 case SND_STA: /* Starting position (= PSEND) */
5333 if ((x = cmnum("0-based position","0",10,&y,xxstring)) < 0)
5338 case SND_TYP: /* /TYPE */
5340 if ((x = cmkey(txtbin,3,"","all",xxstring)) < 0)
5342 pv[n].ival = (x == 2) ? -1 : x;
5346 case SND_CSL: /* Local character set */
5347 case SND_CSR: /* Remote (server) charset */
5348 if ((x = cmkey(fcstab,nfilc,"","",xxstring)) < 0) {
5349 return((x == -3) ? -2 : x);
5355 x_xla = 1; /* Overrides global OFF setting */
5358 case SND_XPA: /* Transparent */
5363 #endif /* NOCSETS */
5367 if (pv[SND_RES].ival > 0) { /* /RECOVER */
5368 if (sndfilter || pv[SND_FLT].ival > 0) {
5369 printf("?Sorry, no /RECOVER or /START if SEND FILTER selected\n");
5373 if (sfttab[0] > 0 && sfttab[SFT_REST] == 0)
5374 printf("WARNING: Server says it doesn't support REST.\n");
5376 #endif /* PIPESEND */
5384 switch (cmresult.fcode) { /* How did we get out of switch loop */
5385 case _CMIFI: /* Input filename */
5386 if (pv[SND_FIL].ival > 0) {
5387 printf("?You may not give a PUT filespec and a /LISTFILE\n");
5391 ckstrncpy(line,cmresult.sresult,LINBUFSIZ); /* Name */
5392 if (pv[SND_ARR].ival > 0)
5393 ckstrncpy(asnambuf,line,CKMAXPATH);
5395 wild = cmresult.nresult; /* Wild flag */
5396 debug(F111,"ftp put wild",line,wild);
5397 if (!wild && !recursive && !mput)
5400 case _CMFLD: /* Field */
5401 /* Only allowed with /COMMAND and /ARRAY */
5402 if (pv[SND_FIL].ival > 0) {
5403 printf("?You may not give a PUT filespec and a /LISTFILE\n");
5407 /* For MPUT it's OK to have filespecs that don't match any files */
5410 if (pv[SND_CMD].ival < 1 && pv[SND_ARR].ival < 1) {
5413 printf("?Off limits: %s\n",cmresult.sresult);
5416 printf("?%s - \"%s\"\n",
5417 iswild(cmresult.sresult) ?
5418 "No files match" : "File not found",
5424 ckstrncpy(line,cmresult.sresult,LINBUFSIZ);
5425 if (pv[SND_ARR].ival > 0)
5426 ckstrncpy(asnambuf,line,CKMAXPATH);
5428 case _CMCFM: /* Confirmation */
5432 printf("?Unexpected function code: %d\n",cmresult.fcode);
5436 debug(F110,"ftp put string",s,0);
5437 debug(F101,"ftp put confirmed","",confirmed);
5439 /* Save and change protocol and transfer mode */
5440 /* Global values are restored in main parse loop */
5445 g_skipbup = skipbup;
5447 if (pv[SND_NOB].ival > -1) { /* /NOBACKUP (skip backup file) */
5448 g_skipbup = skipbup;
5451 if (pv[SND_TYP].ival > -1) { /* /TYPE */
5452 xfiletype = pv[SND_TYP].ival;
5456 if (pv[SND_BIN].ival > 0) { /* /BINARY really means binary... */
5457 forcetype = 1; /* So skip file scan */
5458 ftp_typ = FTT_BIN; /* Set binary */
5459 } else if (pv[SND_TXT].ival > 0) { /* Similarly for /TEXT... */
5462 } else if (pv[SND_TEN].ival > 0) { /* and /TENEX*/
5465 } else if (ftp_cmdlin && ftp_xfermode == XMODE_M) {
5472 if (pv[SND_CMD].ival > 0) { /* /COMMAND - strip any braces */
5473 debug(F110,"PUT /COMMAND before stripping",s,0);
5475 debug(F110,"PUT /COMMAND after stripping",s,0);
5477 printf("?Sorry, a command to send from is required\n");
5483 #endif /* PIPESEND */
5485 /* Set up /MOVE and /RENAME */
5487 if (pv[SND_DEL].ival > 0 &&
5488 (pv[SND_MOV].ival > 0 || pv[SND_REN].ival > 0)) {
5489 printf("?Sorry, /DELETE conflicts with /MOVE or /RENAME\n");
5494 if (pv[SND_MOV].ival > 0) {
5496 char * p = pv[SND_MOV].sval;
5498 if (!isdir(p)) { /* Check directory */
5501 s = (char *)malloc(len + 4);
5503 strcpy(s,p); /* safe */
5505 if (s[len-1] != ':') { s[len++] = ':'; s[len] = NUL; }
5507 if (s[len-1] != '/') { s[len++] = '/'; s[len] = NUL; }
5508 #endif /* datageneral */
5515 #endif /* NOMKDIR */
5518 printf("?Can't create \"%s\"\n",p);
5524 printf("?Directory \"%s\" not found\n",p);
5527 #endif /* CK_MKDIR */
5529 makestr(&snd_move,p);
5531 #endif /* CK_TMPDIR */
5533 if (pv[SND_REN].ival > 0) { /* /RENAME */
5534 char * p = pv[SND_REN].sval;
5537 printf("?New name required for /RENAME\n");
5543 /* If name given is wild, rename string must contain variables */
5548 if (!strcmp(tmpbuf,p)) {
5550 "?/RENAME for file group must contain variables such as \\v(filename)\n"
5557 makestr(&snd_rename,p);
5558 debug(F110,"FTP snd_rename",snd_rename,0);
5560 if (pv[SND_SRN].ival > 0) { /* /SERVER-RENAME */
5561 char * p = pv[SND_SRN].sval;
5564 printf("?New name required for /SERVER-RENAME\n");
5574 if (!strcmp(tmpbuf,p)) {
5576 "?/SERVER-RENAME for file group must contain variables such as \\v(filename)\n"
5583 makestr(&srv_renam,p);
5584 debug(F110,"ftp put srv_renam",srv_renam,0);
5586 if (!confirmed) { /* CR not typed yet, get more fields */
5588 if (mput) { /* MPUT or MMOVE */
5589 nfils = 0; /* We already have the first one */
5591 if (cmresult.fcode == _CMIFI) {
5592 /* First filespec is valid */
5593 msfiles[nfils++] = line; /* Store pointer */
5594 lp = line + (int)strlen(line) + 1; /* Point past it */
5595 debug(F111,"ftp put mput",msfiles[nfils-1],nfils-1);
5597 /* First filespec matches no files */
5598 debug(F110,"ftp put mput skipping first filespec",
5604 /* Parse a filespec, a "field", or confirmation */
5606 cmfdbi(&sf, /* 1st FDB - file to send */
5610 "", /* addtl string data */
5611 nolinks | x_recurse, /* addtl numeric data 1 */
5612 0, /* dirflg 0 means "not dirs only" */
5617 cmfdbi(&fl, /* 2nd FDB - local filespec */
5621 "", /* addtl string data */
5622 0, /* addtl numeric data 1 */
5623 0, /* addtl numeric data 2 */
5628 cmfdbi(&cm, /* 3rd FDB - Confirmation */
5640 while (!confirmed) { /* Get more filenames */
5641 x = cmfdb(&sf); /* Parse something */
5642 debug(F101,"ftp put cmfdb B","",x);
5643 debug(F101,"ftp put fcode B","",cmresult.fcode);
5644 if (x < 0) /* Error */
5645 goto xputx; /* or reparse needed */
5646 switch (cmresult.fcode) {
5647 case _CMCFM: /* End of command */
5650 debug(F100,"ftp put mput no files match","",0);
5651 printf("?No files match MPUT list\n");
5656 case _CMFLD: /* No match */
5657 debug(F110,"ftp put mput skipping",cmresult.sresult,0);
5659 case _CMIFI: /* Good match */
5660 s = cmresult.sresult;
5661 msfiles[nfils++] = lp; /* Got one, count, point to it, */
5662 p = lp; /* remember pointer, */
5663 while ((*lp++ = *s++)) /* and copy it into buffer */
5664 if (lp > (line + LINBUFSIZ)) { /* Avoid memory leak */
5665 printf("?MPUT list too long\n");
5670 debug(F111,"ftp put mput adding",msfiles[nfils-1],nfils-1);
5671 if (nfils == 1) /* Take care of \v(filespec) */
5674 zfnqfp(p,TMPBUFSIZ,tmpbuf);
5677 if (((int)strlen(fspec) + (int)strlen(p) + 1) < fspeclen) {
5678 strcat(fspec,p); /* safe */
5679 strcat(fspec," "); /* safe */
5682 printf("WARNING - \\v(filespec) buffer overflow\n");
5684 debug(F101,"doxput filespec buffer overflow","",0);
5685 #endif /* COMMENT */
5689 #endif /* NOMSEND */
5690 } else { /* Regular PUT */
5692 if ((x = cmtxt(wild ?
5693 "\nOptional as-name template containing replacement variables \
5694 like \\v(filename)" :
5695 "Optional name to send it with",
5699 if (p) if (!*p) p = NULL;
5703 makestr(&(pv[SND_ASN].sval),p);
5704 if (pv[SND_ASN].sval)
5705 pv[SND_ASN].ival = 1;
5706 debug(F110,"ftp put /as-name 2",pv[SND_ASN].sval,0);
5710 /* Set cmarg2 from as-name, however we got it. */
5713 if (pv[SND_ASN].ival > 0 && pv[SND_ASN].sval && !asnambuf[0]) {
5715 p = brstrip(pv[SND_ASN].sval);
5716 ckstrncpy(asnambuf,p,CKMAXPATH+1);
5718 debug(F110,"ftp put asnambuf",asnambuf,0);
5720 if (pv[SND_FIL].ival > 0) {
5722 if (zopeni(ZMFILE,pv[SND_FIL].sval) < 1) {
5723 debug(F110,"ftp put can't open",pv[SND_FIL].sval,0);
5724 printf("?Failure to open %s\n",pv[SND_FIL].sval);
5728 makestr(&filefile,pv[SND_FIL].sval); /* Open, remember name */
5729 debug(F110,"ftp PUT /LISTFILE opened",filefile,0);
5733 if (confirmed && !line[0] && !filefile) {
5735 if (filehead) { /* OK if we have a SEND-LIST */
5736 nfils = filesinlist;
5737 sndsrc = nfils; /* Like MSEND */
5738 addlist = 1; /* But using a different list... */
5739 filenext = filehead;
5742 #endif /* NOMSEND */
5743 printf("?Filename required but not given\n");
5748 addlist = 0; /* Don't use SEND-LIST. */
5749 #endif /* NOMSEND */
5751 if (mput) { /* MPUT (rather than PUT) */
5753 cmlist = msfiles; /* List of filespecs */
5754 sndsrc = nfils; /* rather filespec and as-name */
5755 #endif /* NOMSEND */
5757 } else if (filefile) { /* File contains list of filenames */
5764 } else if (pv[SND_ARR].ival < 1 && pv[SND_CMD].ival < 1) {
5766 /* Not MSEND, MMOVE, /LIST, or /ARRAY */
5767 nfils = sndsrc = -1;
5770 printf("?Read access denied - \"%s\"\n", s);
5775 if (s != line) /* We might already have done this. */
5776 ckstrncpy(line,s,LINBUFSIZ); /* Copy of string just parsed. */
5779 debug(F110,"doxput line=s",line,0);
5781 cmarg = line; /* File to send */
5784 zfnqfp(cmarg,fspeclen,fspec); /* Get full name */
5785 #endif /* NOMSEND */
5787 if (!mput) { /* For all but MPUT... */
5789 if (pv[SND_CMD].ival > 0) /* /COMMAND sets pipesend flag */
5791 debug(F101,"ftp put /COMMAND pipesend","",pipesend);
5792 if (pipesend && filefile) {
5793 printf("?Invalid switch combination\n");
5797 #endif /* PIPESEND */
5800 /* If as-name given and filespec is wild, as-name must contain variables */
5801 if ((wild || mput) && asnambuf[0]) {
5804 zzstring(asnambuf,&s,&x);
5805 if (!strcmp(tmpbuf,asnambuf)) {
5807 "?As-name for file group must contain variables such as \\v(filename)\n"
5818 if (pv[SND_SHH].ival > 0) { /* SEND /QUIET... */
5820 debug(F101,"ftp put display","",fdispla);
5827 #ifdef PUTARRAY /* SEND /ARRAY... */
5828 if (pv[SND_ARR].ival > 0) {
5829 if (!ap) { x = -2; goto xputx; } /* (shouldn't happen) */
5830 if (range[0] == -1) /* If low end of range not specified */
5831 range[0] = 1; /* default to 1 */
5832 if (range[1] == -1) /* If high not specified */
5833 range[1] = a_dim[arrayx]; /* default to size of array */
5834 if ((range[0] < 0) || /* Check range */
5835 (range[0] > a_dim[arrayx]) ||
5836 (range[1] < range[0]) ||
5837 (range[1] > a_dim[arrayx])) {
5838 printf("?Bad array range - [%d:%d]\n",range[0],range[1]);
5842 sndarray = ap; /* Array pointer */
5843 sndxin = arrayx; /* Array index */
5844 sndxlo = range[0]; /* Array range */
5846 sndxnam[7] = (char)((sndxin == 1) ? 64 : sndxin + ARRAYBASE);
5848 ckstrncpy(asnambuf,sndxnam,CKMAXPATH);
5851 #endif /* PUTARRAY */
5855 if (pv[SND_ARR].ival < 1) { /* File selection & disposition... */
5856 if (pv[SND_DEL].ival > 0) /* /DELETE was specified */
5858 if (pv[SND_AFT].ival > 0) /* Copy SEND criteria */
5859 ckstrncpy(sndafter,pv[SND_AFT].sval,19);
5860 if (pv[SND_BEF].ival > 0)
5861 ckstrncpy(sndbefore,pv[SND_BEF].sval,19);
5862 if (pv[SND_NAF].ival > 0)
5863 ckstrncpy(sndnafter,pv[SND_NAF].sval,19);
5864 if (pv[SND_NBE].ival > 0)
5865 ckstrncpy(sndnbefore,pv[SND_NBE].sval,19);
5866 if (pv[SND_EXC].ival > 0)
5867 makelist(pv[SND_EXC].sval,sndexcept,NSNDEXCEPT);
5868 if (pv[SND_SMA].ival > -1)
5869 sndsmaller = pv[SND_SMA].wval;
5870 if (pv[SND_LAR].ival > -1)
5871 sndlarger = pv[SND_LAR].wval;
5872 if (pv[SND_NAM].ival > -1)
5873 x_cnv = pv[SND_NAM].ival;
5874 if (pv[SND_USN].ival > -1)
5875 x_usn = pv[SND_USN].ival;
5876 if (pv[SND_ERR].ival > -1)
5877 puterror = pv[SND_ERR].ival;
5880 if (pv[SND_UPD].ival > 0) {
5882 printf("?Conflicting switches: /UPDATE /UNIQUE\n");
5886 putflags |= PUT_UPD;
5890 /* This works but it's useless, maybe dangerous */
5891 if (pv[SND_DIF].ival > 0) {
5893 printf("?Conflicting switches: /DATES-DIFFER /UNIQUE\n");
5897 putflags |= PUT_DIF;
5900 #endif /* COMMENT */
5901 #endif /* DOUPDATE */
5903 if (pv[SND_SIM].ival > 0)
5904 putflags |= PUT_SIM;
5906 if (pv[SND_PRM].ival > -1) {
5909 printf("?Conflicting switches: /PERMISSIONS /UNIQUE\n");
5913 x_prm = pv[SND_PRM].ival;
5915 printf("?/PERMISSIONS switch is not supported\n");
5919 if (pv[SND_RES].ival > 0) {
5921 printf("?PUT /RESTART can't be used because SIZE disabled.\n");
5925 if (x_usn || putflags) {
5926 printf("?Conflicting switches: /RECOVER %s\n",
5927 x_usn && putflags ? "/UNIQUE /UPDATE" :
5928 (x_usn ? "/UNIQUE" : "/UPDATE")
5935 (x_csl == FC_UCS2 ||
5938 x_csr == FC_UTF8)) {
5939 printf("?/RECOVER can not be used with Unicode translation\n");
5943 #endif /* NOCSETS */
5946 #endif /* FTP_RESTART */
5948 debug(F101,"ftp PUT restart","",putflags & PUT_RES);
5949 debug(F101,"ftp PUT update","",putflags & PUT_UPD);
5952 if (pv[SND_FLT].ival > 0) { /* Have SEND FILTER? */
5953 if (!pv[SND_FLT].sval) {
5956 sndfilter = (char *) malloc((int) strlen(pv[SND_FLT].sval) + 1);
5957 if (sndfilter) strcpy(sndfilter,pv[SND_FLT].sval); /* safe */
5959 debug(F110,"ftp put /FILTER", sndfilter, 0);
5961 if (sndfilter || pipesend) /* No /UPDATE or /RESTART */
5962 if (putflags) /* with pipes or filters */
5964 #endif /* PIPESEND */
5966 tfc = (CK_OFF_T)0; /* Initialize stats and counters */
5971 if (wild) /* (is this necessary?) */
5974 t0 = gmstimer(); /* Record starting time */
5976 done = 0; /* Loop control */
5981 while (!done && !cancelgroup) { /* Loop for all files */
5982 /* or until canceled. */
5985 If we are using a proxy, we don't use the local file list;
5986 instead we use the list on the remote machine which we want
5987 sent to someone else, and we use remglob() to get the names.
5988 But in that case we shouldn't even be executing this routine;
5991 #endif /* FTP_PROXY */
5994 x = gnfile(); /* Get next file from list(s) */
5996 if (x == 0) /* (see gnfile() comments...) */
5998 debug(F111,"FTP PUT gnfile",filnam,x);
5999 debug(F111,"FTP PUT binary",filnam,binary);
6002 case 1: /* File to send */
6005 if (asnambuf[0]) { /* As-name */
6006 int n; char *p; /* to be evaluated... */
6009 zzstring(asnambuf,&p,&n);
6011 debug(F110,"ftp put asname",s2,0);
6014 rc = putfile(cx, /* Function (PUT, APPEND) */
6015 filnam, s2, /* Name to send, as-name */
6016 forcetype, moving, /* Parameters from switches... */
6017 snd_move, snd_rename, srv_renam,
6018 x_cnv, x_usn, xfiletype, x_prm,
6020 x_csl, (!x_xla ? -1 : x_csr),
6023 #endif /* NOCSETS */
6026 debug(F111,"ftp put putfile rc",filnam,rc);
6027 debug(F111,"ftp put putfile cancelfile",filnam,cancelfile);
6028 debug(F111,"ftp put putfile cancelgroup",filnam,cancelgroup);
6039 printf("?Fatal upload error: %s\n",filnam);
6044 case 0: /* No more files, done */
6048 printf("?%s: file not found - \"%s\"\n",
6049 puterror ? "Fatal" : "Warning",
6060 printf("?Fatal: file not found - \"%s\"\n", filnam);
6065 continue; /* Not readable, keep going */
6068 printf("?Fatal: Read access denied - \"%s\"\n", filnam);
6073 printf("?Warning access denied - \"%s\"\n", filnam);
6076 case -4: /* Canceled */
6079 #endif /* COMMENT */
6081 printf("?Too many files match\n");
6086 printf("?No files selected\n");
6090 printf("?getnextfile() - unknown failure\n");
6098 } else if (!doftpcdup())
6105 else if (cancelfile && good < 1)
6114 t1 = gmstimer(); /* End time */
6115 sec = (CKFLOAT)((CKFLOAT)(t1 - t0) / 1000.0); /* Stats */
6116 if (!sec) sec = 0.001;
6119 sec = (t1 - t0) / 1000;
6121 #endif /* GFTIMER */
6122 tfcps = (long) (tfc / sec);
6124 lastxfer = W_FTP|W_SEND;
6127 ftscreen(status > 0 ? SCR_TC : SCR_CW, 0, (CK_OFF_T)0, "");
6129 for (i = 0; i <= SND_MAX; i++) { /* Free malloc'd memory */
6133 ftreset(); /* Undo switch effects */
6139 static char ** mgetlist = NULL; /* For MGET */
6140 static int mgetn = 0, mgetx = 0;
6141 static char xtmpbuf[4096];
6146 Get files specified by -g command-line option.
6147 File list is set up in cmlist[] by ckuusy.c; nfils is length of list.
6150 cmdlinget(stay) int stay; {
6151 int i, x, rc = 0, done = 0, good = 0, status = 0, append = 0;
6152 int lcs = -1, rcs = -1, xlate = 0;
6156 char * s, * s2, * s3;
6157 ULONG t0, t1; /* Times for stats */
6162 #endif /* GFTIMER */
6164 if (quiet) { /* -q really means quiet */
6174 what = W_FTP|W_RECV;
6179 havesize = (CK_OFF_T)-1;
6180 makestr(&havemdtm,NULL);
6188 debug(F101,"ftp cmdlinget nfils","",nfils);
6190 if (ftp_cnv == CNV_AUTO) { /* Name conversion is auto */
6191 if (alike) { /* If server & client are alike */
6192 nc = 0; /* no conversion */
6193 } else { /* If they are different */
6194 if (servertype == SYS_UNIX || servertype == SYS_WIN32)
6195 nc = -1; /* only minimal conversions needed */
6196 else /* otherwise */
6197 nc = 1; /* full conversion */
6199 } else /* Not auto - do what user said */
6203 doexit(BAD_EXIT,-1);
6205 t0 = gmstimer(); /* Starting time for this batch */
6208 if (xlate) { /* SET FTP CHARACTER-SET-TRANSLATION */
6209 lcs = ftp_csl; /* Local charset */
6210 if (lcs < 0) lcs = fcharset;
6211 if (lcs < 0) xlate = 0;
6213 if (xlate) { /* Still ON? */
6214 rcs = ftp_csx; /* Remote (Server) charset */
6215 if (rcs < 0) rcs = ftp_csr;
6216 if (rcs < 0) xlate = 0;
6218 #endif /* NOCSETS */
6220 If we have only one file and it is a directory, then we ask for a
6221 listing of its contents, rather than retrieving the directory file
6222 itself. This is what (e.g.) Netscape does.
6225 if (doftpcwd((char *)cmlist[mgetx],-1)) {
6226 /* If we can CD to it, it must be a directory */
6228 cmlist[mgetx] = "*";
6231 (recvrequest("LIST","-","","wb",0,0,NULL,xlate,lcs,rcs)==0);
6237 The following is to work around UNIX servers which, when given a command
6238 like "NLST path/blah" (not wild) returns the basename without the path.
6240 if (!done && servertype == SYS_UNIX && nfils == 1) {
6241 mget = iswild(cmlist[mgetx]);
6243 if (!mget && !done) { /* Invoked by command-line FTP URL */
6245 printf("DOING GET...\n");
6247 cancelfile = 0; /* This file not canceled yet */
6249 rc = 0; /* Initial return code */
6250 fsize = (CK_OFF_T)-1;
6252 x = ftpcmd("SIZE",s,lcs,rcs,ftp_vbm); /* Get remote file's size */
6253 if (x == REPLY_COMPLETE)
6254 fsize = ckatofs(&ftp_reply_str[4]);
6256 ckstrncpy(filnam,s,CKMAXPATH); /* For \v(filename) */
6257 debug(F111,"ftp cmdlinget filnam",filnam,fsize);
6259 nzrtol(s,tmpbuf,nc,0,CKMAXPATH); /* Strip path and maybe convert */
6262 /* If local file already exists, take collision action */
6264 if (zchki(s2) > -1) {
6266 case XYFX_A: /* Append */
6269 case XYFX_R: /* Rename */
6270 case XYFX_B: { /* Backup */
6273 znewn(s2,&p); /* Make unique name */
6274 debug(F110,"ftp cmdlinget znewn",p,0);
6275 if (ftp_fnc == XYFX_B) { /* Backup existing file */
6277 debug(F111,"ftp cmdlinget backup zrename",p,x);
6278 } else { /* Rename incoming file */
6279 x = ckstrncpy(tmpbuf,p,CKMAXPATH+1);
6281 debug(F111,"ftp cmdlinget rename incoming",p,x);
6284 printf("?Backup/Rename failed\n");
6285 return(success = 0);
6289 case XYFX_D: /* Discard */
6290 ftscreen(SCR_FN,'F',(CK_OFF_T)0,s);
6291 ftscreen(SCR_ST,ST_SKIP,(CK_OFF_T)SKP_NAM,s);
6292 tlog(F100," refused: name","",0);
6293 debug(F110,"ftp cmdlinget skip name",s2,0);
6296 case XYFX_X: /* Overwrite */
6297 case XYFX_U: /* Update (already handled above) */
6298 case XYFX_M: /* ditto */
6302 rc = getfile(s, /* Remote name */
6303 s2, /* Local name */
6304 0, /* Recover/Restart */
6305 append, /* Append */
6306 NULL, /* Pipename */
6307 0, /* Translate charsets */
6308 -1, /* File charset (none) */
6309 -1 /* Server charset (none) */
6311 debug(F111,"ftp cmdlinget rc",s,rc);
6312 debug(F111,"ftp cmdlinget cancelfile",s,cancelfile);
6313 debug(F111,"ftp cmdlinget cancelgroup",s,cancelgroup);
6315 if (rc < 0 && haveurl && s[0] == '/') /* URL failed - try again */
6316 rc = getfile(&s[1], /* Remote name without leading '/' */
6317 s2, /* Local name */
6318 0, /* Recover/Restart */
6319 append, /* Append */
6320 NULL, /* Pipename */
6321 0, /* Translate charsets */
6322 -1, /* File charset (none) */
6323 -1 /* Server charset (none) */
6336 #endif /* FTP_TIMEOUT */
6343 if (ftp_deb && !done)
6344 printf("DOING MGET...\n");
6345 while (!done && !cancelgroup) {
6346 cancelfile = 0; /* This file not canceled yet */
6347 s = (char *)remote_files(first,(CHAR *)cmlist[mgetx],NULL,0);
6353 s = (char *)remote_files(first,(CHAR *)cmlist[mgetx],NULL,0);
6356 debug(F111,"ftp cmdlinget remote_files B",s,0);
6363 The semantics of NLST are ill-defined. Suppose we have just sent
6364 NLST /path/[a-z]*. Most servers send back names like /path/foo,
6365 /path/bar, etc. But some send back only foo and bar, and subsequent
6366 RETR commands based on the pathless names are not going to work.
6368 if (servertype == SYS_UNIX && !ckstrchr(s,'/')) {
6369 if ((s3 = ckstrrchr(cmlist[mgetx],'/'))) {
6370 int len, left = 4096;
6371 char * tmp = xtmpbuf;
6372 len = s3 - cmlist[mgetx] + 1;
6373 ckstrncpy(tmp,cmlist[mgetx],left);
6376 ckstrncpy(tmp,s,left);
6378 debug(F111,"ftp cmdlinget remote_files X",s,0);
6381 first = 0; /* Not first any more */
6383 debug(F111,"ftp cmdlinget havetype",s,havetype);
6384 if (havetype > 0 && havetype != FTYP_FILE) { /* Server says not file */
6385 debug(F110,"ftp cmdlinget not-a-file",s,0);
6388 rc = 0; /* Initial return code */
6389 if (havesize > (CK_OFF_T)-1) { /* Already have file size? */
6391 } else { /* No - must ask server */
6393 Prior to sending the NLST command we necessarily put the
6394 server into ASCII mode. We must now put it back into the
6395 the requested mode so the upcoming SIZE command returns
6396 right kind of size; this is especially important for
6397 GET /RECOVER; otherwise the server returns the "ASCII" size
6398 of the file, rather than its true size.
6400 changetype(ftp_typ,0); /* Change to requested type */
6401 fsize = (CK_OFF_T)-1;
6403 x = ftpcmd("SIZE",s,lcs,rcs,ftp_vbm);
6404 if (x == REPLY_COMPLETE)
6405 fsize = ckatofs(&ftp_reply_str[4]);
6408 ckstrncpy(filnam,s,CKMAXPATH); /* For \v(filename) */
6409 debug(F111,"ftp cmdlinget filnam",filnam,fsize);
6411 nzrtol(s,tmpbuf,nc,0,CKMAXPATH); /* Strip path and maybe convert */
6414 /* If local file already exists, take collision action */
6416 if (zchki(s2) > -1) {
6418 case XYFX_A: /* Append */
6421 case XYFX_R: /* Rename */
6422 case XYFX_B: { /* Backup */
6425 znewn(s2,&p); /* Make unique name */
6426 debug(F110,"ftp cmdlinget znewn",p,0);
6427 if (ftp_fnc == XYFX_B) { /* Backup existing file */
6429 debug(F111,"ftp cmdlinget backup zrename",p,x);
6430 } else { /* Rename incoming file */
6431 x = ckstrncpy(tmpbuf,p,CKMAXPATH+1);
6433 debug(F111,"ftp cmdlinget rename incoming",p,x);
6436 printf("?Backup/Rename failed\n");
6437 return(success = 0);
6441 case XYFX_D: /* Discard */
6442 ftscreen(SCR_FN,'F',(CK_OFF_T)0,s);
6443 ftscreen(SCR_ST,ST_SKIP,(CK_OFF_T)SKP_NAM,s);
6444 tlog(F100," refused: name","",0);
6445 debug(F110,"ftp cmdlinget skip name",s2,0);
6447 case XYFX_X: /* Overwrite */
6448 case XYFX_U: /* Update (already handled above) */
6449 case XYFX_M: /* ditto */
6453 /* ^^^ ADD CHARSET STUFF HERE ^^^ */
6454 rc = getfile(s, /* Remote name */
6455 s2, /* Local name */
6456 0, /* Recover/Restart */
6457 append, /* Append */
6458 NULL, /* Pipename */
6459 0, /* Translate charsets */
6460 -1, /* File charset (none) */
6461 -1 /* Server charset (none) */
6463 debug(F111,"ftp cmdlinget rc",s,rc);
6464 debug(F111,"ftp cmdlinget cancelfile",s,cancelfile);
6465 debug(F111,"ftp cmdlinget cancelgroup",s,cancelgroup);
6478 #endif /* FTP_TIMEOUT */
6492 else if (cancelfile && good < 1)
6498 t1 = gmstimer(); /* End time */
6499 sec = (CKFLOAT)((CKFLOAT)(t1 - t0) / 1000.0); /* Stats */
6500 if (!sec) sec = 0.001;
6503 sec = (t1 - t0) / 1000;
6505 #endif /* GFTIMER */
6507 tfcps = (long) (tfc / sec);
6509 lastxfer = W_FTP|W_RECV;
6512 ftscreen(status > 0 ? SCR_TC : SCR_CW, 0, (CK_OFF_T)0, "");
6514 doexit(success ? GOOD_EXIT : BAD_EXIT, -1);
6518 /* d o f t p g e t -- Parse and execute GET, MGET, MDELETE, ... */
6521 Note: if we wanted to implement /AFTER:, /BEFORE:, etc, we could use
6522 zstrdat() to convert to UTC-based time_t. But it doesn't make sense from
6523 the user-interface perspective, since the server's directory listings show
6524 its own local times and since we don't know what timezone it's in, there's
6525 no way to reconcile our local times with the server's.
6528 doftpget(cx,who) int cx, who; { /* who == 1 for ftp, 0 for kermit */
6529 struct FDB fl, sw, cm;
6530 int i, n, rc, getval = 0, mget = 0, done = 0, pipesave = 0;
6531 int x_cnv = 0, x_prm = 0, restart = 0, status = 0, good = 0;
6532 int x_fnc = 0, first = 0, skipthis = 0, append = 0, selected = 0;
6533 int renaming = 0, mdel = 0, listfile = 0, updating = 0, getone = 0;
6534 int moving = 0, deleting = 0, toscreen = 0, haspath = 0;
6537 CK_OFF_T getlarger = (CK_OFF_T)-1;
6538 CK_OFF_T getsmaller = (CK_OFF_T)-1;
6539 char * msg, * s, * s2, * nam, * pipename = NULL, * pn = NULL;
6540 char * src = "", * local = "";
6543 int x_csl = -1, x_csr = -1; /* Local and remote charsets */
6545 char c; /* Worker char */
6546 ULONG t0 = 0L, t1; /* Times for stats */
6551 #endif /* GFTIMER */
6553 struct stringint pv[SND_MAX+1]; /* Temporary array for switch values */
6555 success = 0; /* Assume failure */
6556 forcetype = 0; /* No /TEXT or /BINARY given yet */
6557 restart = 0; /* No restart yet */
6558 out2screen = 0; /* No TO-SCREEN switch given yet */
6559 mgetmethod = 0; /* No NLST or MLSD switch yet */
6566 x_cnv = ftp_cnv; /* Filename conversion */
6567 if (x_cnv == CNV_AUTO) { /* Name conversion is auto */
6568 if (alike) { /* If server & client are alike */
6569 x_cnv = 0; /* no conversion */
6570 } else { /* If they are different */
6571 if (servertype == SYS_UNIX || servertype == SYS_WIN32)
6572 x_cnv = -1; /* only minimal conversions needed */
6573 else /* otherwise */
6574 x_cnv = 1; /* full conversion */
6576 } else /* Not auto - do what user said */
6579 x_prm = ftp_prm; /* Permissions */
6580 if (x_prm == SET_AUTO) /* Permissions AUTO */
6584 x_csr = ftp_csr; /* Inherit global server charset */
6585 x_csl = ftp_csl; /* Inherit global local charset */
6586 if (x_csl < 0) /* If none, use current */
6587 x_csl = fcharset; /* file character-set. */
6588 x_xla = ftp_xla; /* Translation On/Off */
6589 #endif /* NOCSETS */
6591 geterror = ftp_err; /* Inherit global error action. */
6592 asnambuf[0] = NUL; /* No as-name yet. */
6593 pipesave = pipesend;
6597 havesize = (CK_OFF_T)-1;
6598 makestr(&havemdtm,NULL);
6600 if (g_ftp_typ > -1) { /* Restore TYPE if saved */
6601 ftp_typ = g_ftp_typ;
6602 /* g_ftp_typ = -1; */
6604 for (i = 0; i <= SND_MAX; i++) { /* Initialize switch values */
6605 pv[i].sval = NULL; /* to null pointers */
6606 pv[i].ival = -1; /* and -1 int values */
6607 pv[i].wval = (CK_OFF_T)-1; /* and -1 wide values */
6609 zclose(ZMFILE); /* In case it was left open */
6611 x_fnc = ftp_fnc > -1 ? ftp_fnc : fncact; /* Filename collision action */
6613 if (fp_nml) { /* Reset /NAMELIST */
6614 if (fp_nml != stdout)
6618 makestr(&ftp_nml,NULL);
6620 /* Initialize list of remote filespecs */
6623 mgetlist = (char **)malloc(MGETMAX * sizeof(char *));
6625 printf("?Memory allocation failure - MGET list\n");
6628 for (i = 0; i < MGETMAX; i++)
6631 mgetn = 0; /* Number of mget arguments */
6632 mgetx = 0; /* Current arg */
6634 if (who == 0) { /* Called with unprefixed command */
6635 if (cx == XXGET || cx == XXREGET || cx == XXRETR)
6638 case XXREGET: pv[SND_RES].ival = 1; break;
6639 case XXRETR: pv[SND_DEL].ival = 1; break;
6641 case XXMGET: mget++; break;
6643 } else { /* FTP command */
6644 if (cx == FTP_GET || cx == FTP_RGE)
6647 case FTP_DEL: /* (fall thru on purpose) */
6648 case FTP_MDE: mdel++; /* (ditto) */
6649 case FTP_GET: /* (ditto) */
6650 case FTP_MGE: mget++; break;
6651 case FTP_RGE: pv[SND_RES].ival = 1; break;
6654 cmfdbi(&sw, /* First FDB - command switches */
6656 "Remote filename;\n or switch", /* hlpmsg */
6658 "", /* addtl string data */
6659 mdel ? ndelswi : ngetswi, /* addtl numeric data 1: tbl size */
6660 4, /* addtl numeric data 2: 4 = cmswi */
6661 xxstring, /* Processing function */
6662 mdel ? delswi : getswi, /* Keyword table */
6663 &fl /* Pointer to next FDB */
6665 cmfdbi(&fl, /* 2nd FDB - remote filename */
6669 "", /* addtl string data */
6670 0, /* addtl numeric data 1 */
6671 0, /* addtl numeric data 2 */
6676 cmfdbi(&cm, /* 3rd FDB - Confirmation */
6680 "", /* addtl string data */
6681 0, /* addtl numeric data 1 */
6682 0, /* addtl numeric data 2 */
6688 while (1) { /* Parse 0 or more switches */
6689 x = cmfdb(&sw); /* Parse something */
6690 debug(F101,"ftp get cmfdb","",x);
6691 if (x < 0) /* Error */
6692 goto xgetx; /* or reparse needed */
6693 if (cmresult.fcode != _CMKEY) /* Break out of loop if not a switch */
6695 c = cmgbrk(); /* Get break character */
6696 getval = (c == ':' || c == '='); /* to see how they ended the switch */
6697 if (getval && !(cmresult.kflags & CM_ARG)) {
6698 printf("?This switch does not take arguments\n");
6702 n = cmresult.nresult; /* Numeric result = switch value */
6703 debug(F101,"ftp get switch","",n);
6705 if (!getval && (cmgkwflgs() & CM_ARG)) {
6706 printf("?This switch requires an argument\n");
6710 switch (n) { /* Process the switch */
6711 case SND_ASN: /* /AS-NAME: */
6712 debug(F101,"ftp get /as-name getval","",getval);
6714 if ((x = cmfld("Name to store it under","",&s,NULL)) < 0) {
6716 printf("?name required\n");
6723 makestr(&(pv[n].sval),s);
6727 case SND_BIN: /* /BINARY */
6728 case SND_TXT: /* /TEXT or /ASCII */
6729 case SND_TEN: /* /TENEX */
6730 pv[SND_BIN].ival = 0;
6731 pv[SND_TXT].ival = 0;
6732 pv[SND_TEN].ival = 0;
6737 case SND_CMD: /* These take no args */
6739 printf("?Sorry, system command access is disabled\n");
6744 else if (rcvfilter) {
6745 printf("?Sorry, no PUT /COMMAND when SEND FILTER selected\n");
6749 #endif /* PIPESEND */
6750 sw.hlpmsg = "Command, or switch"; /* Change help message */
6751 pv[n].ival = 1; /* Just set the flag */
6752 pv[SND_ARR].ival = 0;
6754 #endif /* PUTPIPE */
6756 case SND_SHH: /* /QUIET */
6757 case SND_RES: /* /RECOVER (reget) */
6758 case SND_NOB: /* /NOBACKUPFILES */
6759 case SND_DEL: /* /DELETE */
6760 case SND_UPD: /* /UPDATE */
6761 case SND_USN: /* /UNIQUE */
6762 case SND_NOD: /* /NODOTFILES */
6763 case SND_REC: /* /RECOVER */
6764 case SND_MAI: /* /TO-SCREEN */
6765 pv[n].ival = 1; /* Just set the flag */
6768 case SND_DIF: /* /DATES-DIFFER */
6769 pv[SND_COL].ival = XYFX_M; /* Now it's a collision option */
6773 case SND_COL: /* /COLLISION: */
6774 if ((x = cmkey(ftpcolxtab,nftpcolx,"","",xxstring)) < 0)
6777 pv[SND_DIF].ival = 1; /* (phase this out) */
6778 pv[n].ival = x; /* this should be sufficient */
6781 case SND_ERR: /* /ERROR-ACTION */
6782 if ((x = cmkey(qorp,2,"","",xxstring)) < 0)
6787 case SND_EXC: /* Exception list */
6789 if ((x = cmfld("Pattern","",&s,xxstring)) < 0) {
6791 printf("?Pattern required\n");
6796 if (s) if (!*s) s = NULL;
6797 makestr(&(pv[n].sval),s);
6804 debug(F101,"ftp get /filter getval","",getval);
6806 if ((x = cmfld("Filter program to send through","",&s,NULL)) < 0) {
6813 if (pv[SND_MAI].ival < 1) {
6815 /* Make sure they included "\v(...)" */
6816 for (x = 0; x < y; x++) {
6817 if (s[x] != '\\') continue;
6818 if (s[x+1] == 'v') break;
6822 "?Filter must contain a replacement variable for filename.\n"
6830 makestr(&(pv[n].sval),s);
6833 makestr(&(pv[n].sval),NULL);
6836 #endif /* PIPESEND */
6840 if ((x = cmkey(fntab,nfntab,"","automatic",xxstring)) < 0)
6842 debug(F101,"ftp get /filenames","",x);
6846 case SND_SMA: /* Smaller / larger than */
6850 if ((x = cmnumw("Size in bytes","0",10,&y,xxstring)) < 0)
6855 case SND_FIL: /* Name of file containing filnames */
6857 if ((x = cmifi("Name of file containing list of filenames",
6858 "",&s,&y,xxstring)) < 0) {
6860 printf("?Filename required\n");
6864 } else if (y && iswild(s)) {
6865 printf("?Wildcards not allowed BBB\n");
6869 if (s) if (!*s) s = NULL;
6870 makestr(&(pv[n].sval),s);
6875 case SND_MOV: /* MOVE after */
6876 case SND_REN: /* RENAME after */
6877 case SND_SRN: { /* SERVER-RENAME */
6882 "Device and/or directory for incoming file after reception";
6885 m = "New name for incoming file after reception";
6888 m = "New name for source file on server after reception";
6892 if ((x = cmfld(m, "", &s, n == SND_MOV ? xxstring : NULL)) < 0) {
6894 printf("%s\n", n == SND_MOV ?
6895 "?Destination required" :
6896 "?New name required"
6902 makestr(&(pv[n].sval),*s ? brstrip(s) : NULL);
6903 pv[n].ival = (pv[n].sval) ? 1 : 0;
6907 case SND_CSL: /* Local character set */
6908 case SND_CSR: /* Remote (server) charset */
6909 if ((x = cmkey(fcstab,nfilc,"","",xxstring)) < 0)
6910 return((x == -3) ? -2 : x);
6915 x_xla = 1; /* Overrides global OFF setting */
6918 case SND_XPA: /* Transparent */
6923 #endif /* NOCSETS */
6926 if ((x = cmofi("Local filename","-",&s,xxstring)) < 0)
6928 makestr(&ftp_nml,s);
6931 case SND_PAT: /* /PATTERN: */
6933 if ((x = cmfld("Pattern","*", &s, xxstring)) < 0)
6935 makestr(&(pv[n].sval),*s ? brstrip(s) : NULL);
6936 pv[n].ival = (pv[n].sval) ? 1 : 0;
6939 case SND_NLS: /* /NLST */
6940 pv[n].ival = 1; /* Use NLST */
6941 pv[SND_MLS].ival = 0; /* Don't use MLSD */
6944 case SND_MLS: /* /MLSD */
6945 pv[n].ival = 1; /* Use MLSD */
6946 pv[SND_NLS].ival = 0; /* Don't use NLST */
6949 default: /* /AFTER, /PERMISSIONS, etc... */
6950 printf("?Sorry, \"%s\" works only with [M]PUT\n",atmbuf);
6960 For GET, we want to parse an optional as-name, like with PUT.
6961 For MGET, we must parse a list of names, and then send NLST or MLSD
6962 commands for each name separately.
6964 switch (cmresult.fcode) { /* How did we get out of switch loop */
6965 case _CMFLD: /* Field */
6967 s = brstrip(cmresult.sresult);
6968 makestr(&(mgetlist[mgetn++]),s);
6969 while ((x = cmfld("Remote filename","",&s,xxstring)) != -3) {
6972 makestr(&(mgetlist[mgetn++]),brstrip(s));
6973 if (mgetn >= MGETMAX) {
6974 printf("?Too many items in MGET list\n");
6978 if ((x = cmcfm()) < 0)
6981 s = brstrip(cmresult.sresult);
6982 ckstrncpy(line,s,LINBUFSIZ);
6983 if ((x = cmfld("Name to store it under","",&s,xxstring)) < 0)
6987 ckstrncpy(asnambuf,s,CKMAXPATH+1);
6988 if ((x = cmcfm()) < 0)
6992 case _CMCFM: /* Confirmation */
6995 printf("?Unexpected function code: %d\n",cmresult.fcode);
6999 if (pv[SND_REC].ival > 0) /* /RECURSIVE */
7002 if (pv[SND_BIN].ival > 0) { /* /BINARY really means binary... */
7003 forcetype = 1; /* So skip the name-pattern match */
7004 ftp_typ = XYFT_B; /* Set binary */
7005 } else if (pv[SND_TXT].ival > 0) { /* Similarly for /TEXT... */
7008 } else if (pv[SND_TEN].ival > 0) { /* and /TENEX*/
7011 } else if (ftp_cmdlin && ftp_xfermode == XMODE_M) {
7016 if (pv[SND_ASN].ival > 0 && pv[SND_ASN].sval && !asnambuf[0]) {
7018 p = brstrip(pv[SND_ASN].sval); /* As-name */
7019 ckstrncpy(asnambuf,p,CKMAXPATH+1);
7021 debug(F110,"ftp get asnambuf",asnambuf,0);
7024 if (pv[SND_CMD].ival > 0) { /* /COMMAND - strip any braces */
7027 debug(F110,"GET /COMMAND before stripping",p,0);
7029 debug(F110,"GET /COMMAND after stripping",p,0);
7031 printf("?Sorry, a command to write to is required\n");
7038 #endif /* PIPESEND */
7040 /* Set up /MOVE and /RENAME */
7043 /* Conflict exists only for PUT - removed 13 Mar 2006 - fdc */
7044 if (pv[SND_DEL].ival > 0 &&
7045 (pv[SND_MOV].ival > 0 || pv[SND_REN].ival > 0)) {
7046 printf("?Sorry, /DELETE conflicts with /MOVE or /RENAME\n");
7050 #endif /* COMMENT */
7052 if (pv[SND_MOV].ival > 0 && pv[SND_MOV].sval) {
7054 char * p = pv[SND_MOV].sval;
7056 if (!isdir(p)) { /* Check directory */
7059 s = (char *)malloc(len + 4);
7061 strcpy(s,p); /* safe */
7063 if (s[len-1] != ':') { s[len++] = ':'; s[len] = NUL; }
7065 if (s[len-1] != '/') { s[len++] = '/'; s[len] = NUL; }
7066 #endif /* datageneral */
7073 #endif /* NOMKDIR */
7076 printf("?Can't create \"%s\"\n",p);
7082 printf("?Directory \"%s\" not found\n",p);
7085 #endif /* CK_MKDIR */
7087 makestr(&rcv_move,p);
7090 #endif /* CK_TMPDIR */
7092 if (pv[SND_REN].ival > 0) { /* /RENAME */
7093 char * p = pv[SND_REN].sval;
7096 printf("?New name required for /RENAME\n");
7102 /* If name given is wild, rename string must contain variables */
7103 if (mget && !getone) {
7107 if (!strcmp(tmpbuf,p)) {
7109 "?/RENAME for file group must contain variables such as \\v(filename)\n"
7117 makestr(&rcv_rename,p);
7118 debug(F110,"FTP rcv_rename",rcv_rename,0);
7120 if (!cmarg[0] && mgetn == 0 && getone && pv[SND_FIL].ival < 1) {
7121 printf("?Filename required but not given\n");
7124 } else if ((cmarg[0] || mgetn > 0) && pv[SND_FIL].ival > 0) {
7125 printf("?You can't give both /LISTFILE and a remote filename\n");
7129 CHECKCONN(); /* Check connection */
7131 if (pv[SND_COL].ival > -1)
7132 x_fnc = pv[SND_COL].ival;
7135 /* If as-name given for MGET, as-name must contain variables */
7136 if (mget && !getone && asnambuf[0] && x_fnc != XYFX_A) {
7139 zzstring(asnambuf,&s,&x);
7140 if (!strcmp(tmpbuf,asnambuf)) {
7142 "?As-name for MGET must contain variables such as \\v(filename)\n"
7152 if (pv[SND_SHH].ival > 0 || ftp_nml) { /* GET /QUIET... */
7156 if (mdel || ftp_deb)
7160 if (pv[SND_DEL].ival > 0) /* /DELETE was specified */
7162 if (pv[SND_EXC].ival > 0)
7163 makelist(pv[SND_EXC].sval,rcvexcept,NSNDEXCEPT);
7164 if (pv[SND_SMA].wval > -1)
7165 getsmaller = pv[SND_SMA].wval;
7166 if (pv[SND_LAR].wval > -1)
7167 getlarger = pv[SND_LAR].wval;
7168 if (pv[SND_NAM].ival > -1)
7169 x_cnv = pv[SND_NAM].ival;
7170 if (pv[SND_ERR].ival > -1)
7171 geterror = pv[SND_ERR].ival;
7172 if (pv[SND_MAI].ival > -1)
7175 if (pv[SND_NLS].ival > 0) { /* Force NLST or MLSD? */
7176 mgetmethod = SND_NLS;
7178 } else if (pv[SND_MLS].ival > 0) {
7179 mgetmethod = SND_MLS;
7184 if (pv[SND_RES].ival > 0) {
7186 printf("?Sorry, GET /RECOVER requires binary mode\n");
7190 /* Not true - the fact that the initial REST fails does not mean */
7191 /* it will fail here. */
7192 } else if (!okrestart) {
7193 printf("WARNING: Server might not support restart...\n");
7194 #endif /* COMMENT */
7198 #endif /* FTP_RESTART */
7201 if (pv[SND_FLT].ival > 0) { /* Have SEND FILTER? */
7203 printf("?Switch conflict: /FILTER and /COMMAND\n");
7207 makestr(&rcvfilter,pv[SND_FLT].sval);
7208 debug(F110,"ftp get /FILTER", rcvfilter, 0);
7210 if (rcvfilter || pipesend) { /* /RESTART */
7212 if (restart) { /* with pipes or filters */
7213 printf("?Switch conflict: /FILTER or /COMMAND and /RECOVER\n");
7217 #endif /* FTP_RESTART */
7218 if (pv[SND_UPD].ival > 0 || x_fnc == XYFX_M || x_fnc == XYFX_U) {
7220 "?Switch conflict: /FILTER or /COMMAND and Date Checking\n");
7225 #endif /* PIPESEND */
7227 tfc = (CK_OFF_T)0; /* Initialize stats and counters */
7232 if (pv[SND_FIL].ival > 0) {
7233 if (zopeni(ZMFILE,pv[SND_FIL].sval) < 1) {
7234 debug(F111,"ftp get can't open listfile",pv[SND_FIL].sval,errno);
7235 printf("?Failure to open listfile - \"%s\"\n",pv[SND_FIL].sval);
7239 if (zsinl(ZMFILE,tmpbuf,CKMAXPATH) < 0) { /* Read a line */
7240 zclose(ZMFILE); /* Failed */
7241 debug(F110,"ftp get listfile EOF",pv[SND_FIL].sval,0);
7242 printf("?Empty listfile - \"%s\"\n",pv[SND_FIL].sval);
7247 debug(F110,"ftp get listfile first",tmpbuf,0);
7248 makestr(&(mgetlist[0]),tmpbuf);
7250 t0 = gmstimer(); /* Record starting time */
7252 updating = 0; /* Checking dates? */
7253 if (pv[SND_UPD].ival > 0 || (!mdel && x_fnc == XYFX_U))
7255 if (pv[SND_DIF].ival > 0 || x_fnc == XYFX_M)
7257 if (updating) /* These switches force FTP DATES ON */
7260 what = mdel ? W_FTP|W_FT_DELE : W_RECV|W_FTP; /* What we're doing */
7262 cancelgroup = 0; /* Group not canceled yet */
7263 if (!(ftp_xfermode == XMODE_A && patterns && get_auto && !forcetype))
7264 changetype(ftp_typ,0); /* Change to requested type */
7265 binary = ftp_typ; /* For file-transfer display */
7266 first = 1; /* For MGET list */
7267 done = 0; /* Loop control */
7270 if (dldir && !f_tmpdir) { /* If they have a download directory */
7271 if ((s = zgtdir())) { /* Get current directory */
7272 if (zchdir(dldir)) { /* Change to download directory */
7273 ckstrncpy(savdir,s,TMPDIRLEN);
7274 f_tmpdir = 1; /* Remember that we did this */
7278 #endif /* CK_TMPDIR */
7280 if (ftp_nml) { /* /NAMELIST */
7281 debug(F110,"ftp GET ftp_nml",ftp_nml,0);
7282 if (ftp_nml[0] == '-' && ftp_nml[1] == 0)
7285 fp_nml = fopen(ftp_nml, "wb");
7287 printf("?%s: %s\n",ftp_nml,ck_errstr());
7291 while (!done && !cancelgroup) { /* Loop for all files */
7292 /* or until canceled. */
7294 /* do something here if proxy */
7295 #endif /* FTP_PROXY */
7297 rs_len = (CK_OFF_T)0; /* REGET position */
7298 cancelfile = 0; /* This file not canceled yet */
7299 haspath = 0; /* Recalculate this each time thru */
7301 if (getone) { /* GET */
7304 src = line; /* Server name */
7306 debug(F111,"ftp get file",s,0);
7307 } else if (mget) { /* MGET */
7308 src = mgetlist[mgetx];
7309 debug(F111,"ftp mget remote_files A",src,first);
7310 s = (char *)remote_files(first,
7311 (CHAR *)mgetlist[mgetx],
7312 (CHAR *)pv[SND_PAT].sval,
7315 debug(F110,"ftp mget remote_files B",s,0);
7319 if (listfile) { /* Names from listfile */
7322 while (!tmpbuf[0]) {
7323 if (zsinl(ZMFILE,tmpbuf,CKMAXPATH) < 0) {
7325 debug(F110,"ftp get listfile EOF",
7326 pv[SND_FIL].sval,0);
7327 makestr(&(mgetlist[0]),NULL);
7336 makestr(&(mgetlist[0]),tmpbuf);
7337 debug(F110,"ftp get listfile next",tmpbuf,0);
7338 s = (char *)remote_files(first,
7339 (CHAR *)mgetlist[0],
7340 (CHAR *)pv[SND_PAT].sval,
7343 debug(F110,"ftp mget remote_files C",s,0);
7345 ftscreen(SCR_FN,'F',(CK_OFF_T)0,s);
7346 ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,"File not found");
7347 tlog(F110,"ftp get file not found:",s,0);
7350 } else { /* Names from command line */
7353 s = (char *)remote_files(first,
7354 (CHAR *)mgetlist[mgetx],
7355 (CHAR *)pv[SND_PAT].sval,
7361 debug(F111,"ftp mget remote_files D",s,mgetx);
7364 if (!first || mgetx >= mgetn) {
7367 } else if (geterror) {
7377 debug(F111,"ftp mget remote_files E",s,0);
7379 The semantics of NLST are ill-defined. Suppose we have just sent
7380 NLST /path/[a-z]*. Most servers send back names like /path/foo,
7381 /path/bar, etc. But some send back only foo and bar, and subsequent
7382 RETR commands based on the pathless names are not going to work.
7384 if (servertype == SYS_UNIX && !ckstrchr(s,'/')) {
7386 if ((s3 = ckstrrchr(mgetlist[mgetx],'/'))) {
7387 int len, left = 4096;
7388 char * tmp = xtmpbuf;
7389 len = s3 - mgetlist[mgetx] + 1;
7390 ckstrncpy(tmp,mgetlist[mgetx],left);
7393 ckstrncpy(tmp,s,left);
7395 debug(F111,"ftp mget remote_files F",s,0);
7399 skipthis = 0; /* File selection... */
7401 nam = s; /* Filename (without path) */
7402 rc = 0; /* Initial return code */
7405 if (!getone && !skipthis) { /* For MGET and MDELETE... */
7411 debug(F111,"ftp mget havetype",s,havetype);
7412 if (havetype > 0 && havetype != FTYP_FILE) {
7413 /* Server says it's not file... */
7414 debug(F110,"ftp mget not-a-file",s,0);
7418 Explanation: Some ftp servers (such as wu-ftpd) return a recursive list.
7419 But if the client did not ask for a recursive list, we have to ignore any
7420 server files that include a pathname that extends beyond any path that
7421 was included in the user's request.
7423 User's filespec is blah or path/blah (or other non-UNIX syntax). We need to
7424 get the user's path segment. Then, for each incoming file, if it begins
7425 with the same path segment, we must strip it (point past it).
7427 src = mgetlist[mgetx]; /* In case it moved! */
7429 for (i = 0; src[i]; i++) { /* Find rightmost path separator */
7430 if (ispathsep(src[i])) /* in user's pathname */
7436 usrpath = k; /* User path segment length */
7437 debug(F111,"ftp get usrpath",src,usrpath);
7439 p = s; /* Server filename */
7440 while ((c = *p++)) { /* Look for path in server filename */
7443 nam = p; /* Pathless name (for ckmatch) */
7444 srvpath = p - s; /* Server path segment length */
7447 debug(F111,"ftp get srvpath",s,srvpath);
7451 Here we handle the case where the user said "mget foo" where foo is a
7452 directory name, and the server is sending back names like "foo/file1",
7453 "foo/file2", etc. This is a nasty trick but it's necessary because the
7454 user can't compensate by typing "mget foo/" because then the server is
7455 likely to send back "foo//file1, foo//file2" etc, and we still won't
7458 int srclen = 0, srvlen = 0;
7459 if (src) srclen = strlen(src);
7460 if (s) srvlen = strlen(s);
7461 if (src && (srvlen > srclen)) {
7462 if (!strncmp(src,s,srclen) && ispathsep(s[srclen])) {
7463 char * tmpsrc = NULL;
7464 tmpsrc = (char *)malloc(srclen + 2);
7465 strncpy(tmpsrc,src,srclen);
7466 tmpsrc[srclen] = s[srclen];
7467 tmpsrc[srclen+1] = NUL;
7468 free(mgetlist[mgetx]);
7469 mgetlist[mgetx] = tmpsrc;
7471 src = mgetlist[mgetx];
7477 If as-name not given and server filename includes path that matches
7478 the pathname from the user's file specification, we must trim the common
7479 path prefix from the server's name when constructing the local name.
7481 if (src && /* Wed Sep 25 17:27:48 2002 */
7483 !recursive && /* Thu Sep 19 16:11:59 2002 */
7485 !strncmp(src,s,usrpath)) {
7486 s2 = s + usrpath; /* Local name skips past remote path */
7489 /* This doesn't work if the path prefix contains wildcards! */
7490 haspath = (srvpath > usrpath);
7492 { /* Count path segments instead */
7495 for (p = s; *p; p++)
7496 if (ispathsep(*p)) x1++;
7497 for (p = src; *p; p++) {
7498 if (ispathsep(*p)) x2++;
7500 haspath = recursive ? x1 || x2 : x1 > x2;
7501 debug(F111,"ftp get server path segments",s,x1);
7502 debug(F111,"ftp get user path segments",src,x2);
7505 #endif /* COMMENT */
7506 debug(F111,"ftp get haspath",s+usrpath,haspath);
7508 if (haspath) { /* Server file has path segments? */
7509 if (!recursive) { /* [M]GET /RECURSIVE? */
7511 We did not ask for a recursive listing, but the server is sending us one
7512 anyway (as wu-ftpd is wont to do). We get here if the current filename
7513 includes a path segment beyond any path segment we asked for in our
7514 non-recursive [M]GET command. We MUST skip this file.
7516 debug(F111,"ftp get skipping because of path",s,0);
7520 } else if (getone && !skipthis) { /* GET (not MGET) */
7522 while ((c = *p++)) { /* Handle path in local name */
7524 if (recursive) { /* If recursive, keep it */
7527 } else { /* Otherwise lose it. */
7534 if (!*nam) /* Name without path */
7537 if (!skipthis && pv[SND_NOD].ival > 0) { /* /NODOTFILES */
7541 if (!skipthis && rcvexcept[0]) { /* /EXCEPT: list */
7543 for (i = 0; i < NSNDEXCEPT; i++) {
7544 if (!rcvexcept[i]) {
7547 xx = ckmatch(rcvexcept[i], nam, servertype == SYS_UNIX, 1);
7548 debug(F111,"ftp mget /except match",rcvexcept[i],xx);
7550 tlog(F100," refused: exception list","",0);
7551 msg = "Refused: Exception List";
7557 if (!skipthis && pv[SND_NOB].ival > 0) { /* /NOBACKUPFILES */
7563 #endif /* CKREGEX */
7567 if (!x_xla) { /* If translation is off */
7568 x_csl = -2; /* unset the charsets */
7571 ckstrncpy(filnam,s,CKMAXPATH); /* For \v(filename) */
7572 if (!*s2) /* Local name */
7573 s2 = asnambuf; /* As-name */
7575 if (!*s2) /* Sat Nov 16 19:19:39 2002 */
7576 s2 = recursive ? s : nam; /* Fri Jan 10 13:15:19 2003 */
7578 debug(F110,"ftp get filnam ",s,0);
7579 debug(F110,"ftp get asname A",s2,0);
7581 /* Receiving to real file */
7585 #endif /* PIPESEND */
7588 /* Do this here so we can decide whether to skip */
7589 if (cmd_quoting && !skipthis && asnambuf[0]) {
7593 zzstring(asnambuf,&p,&n);
7595 debug(F111,"ftp get asname B",s2,updating);
7599 local = *s2 ? s2 : s;
7601 if (!skipthis && x_fnc == XYFX_D) { /* File Collision = Discard */
7604 debug(F111,"ftp get DISCARD zchki",local,x);
7607 debug(F110,"ftp get skip name",local,0);
7608 tlog(F100," refused: name","",0);
7609 msg = "Refused: Name";
7614 if (!skipthis && updating) { /* If updating and not yet skipping */
7615 if (zchki(local) > -1) {
7616 x = chkmodtime(local,s,0);
7620 debug(F111,"ftp get /dates-diff chkmodtime",local,x);
7622 debug(F111,"ftp get /update chkmodtime",local,x);
7625 if ((updating == 1 && x > 0) || /* /UPDATE */
7626 (updating == 2 && x == 1)) { /* /DATES-DIFFER */
7628 tlog(F100," refused: date","",0);
7629 msg = "Refused: Date";
7630 debug(F110,"ftp get skip date",local,0);
7634 #endif /* DOUPDATE */
7636 /* Initialize file size to -1 in case server doesn't understand */
7637 /* SIZE command, so xxscreen() will know we don't know the size */
7639 fsize = (CK_OFF_T)-1;
7641 /* Ask for size now only if we need it for selection */
7642 /* because if you're going thru a list 100,000 files to select */
7643 /* a small subset, 100,000 SIZE commands can take hours... */
7646 if (!mdel && !skipthis && /* Don't need size for DELE... */
7647 (getsmaller >= (CK_OFF_T)0 || getlarger >= (CK_OFF_T)0)) {
7648 if (havesize >= (CK_OFF_T)0) { /* Already have file size? */
7651 } else { /* No - must ask server */
7653 Prior to sending the NLST command we necessarily put the
7654 server into ASCII mode. We must now put it back into the
7655 the requested mode so the upcoming SIZE command returns
7656 right kind of size; this is especially important for
7657 GET /RECOVER; otherwise the server returns the "ASCII" size
7658 of the file, rather than its true size.
7660 changetype(ftp_typ,0); /* Change to requested type */
7661 fsize = (CK_OFF_T)-1;
7663 x = ftpcmd("SIZE",s,x_csl,x_csr,ftp_vbm);
7664 if (x == REPLY_COMPLETE) {
7665 fsize = ckatofs(&ftp_reply_str[4]);
7671 if (getsmaller >= (CK_OFF_T)0 && fsize >= getsmaller)
7673 if (getlarger >= (CK_OFF_T)0 && fsize <= getlarger)
7676 debug(F111,"ftp get skip size",s,fsize);
7677 tlog(F100," refused: size","",0);
7678 msg = "Refused: Size";
7681 } else if (getone) {
7682 /* SIZE can fail for many reasons. Does the file exist? */
7683 x = ftpcmd("NLST",s,x_csl,x_csr,ftp_vbm);
7684 if (x != REPLY_COMPLETE) {
7685 printf(">>> FILE NOT FOUND: %s\n",s);
7688 #endif /* COMMENT */
7691 if (skipthis) { /* Skipping this file? */
7692 ftscreen(SCR_FN,'F',(CK_OFF_T)0,s);
7694 ftscreen(SCR_ST,ST_ERR,(CK_OFF_T)0,msg);
7696 ftscreen(SCR_ST,ST_SKIP,(CK_OFF_T)0,s);
7699 if (fp_nml) { /* /NAMELIST only - no transfer */
7700 fprintf(fp_nml,"%s\n",s);
7703 if (recursive && haspath && !pipesend
7706 #endif /* PIPESEND */
7713 x = zmkdir(s); /* Try to make the directory */
7714 #endif /* NOMKDIR */
7717 rc = -1; /* Failure is fatal */
7720 ftscreen(SCR_EM,0,(CK_OFF_T)0,
7721 "Directory creation failure");
7729 selected++; /* Count this file as selected */
7732 if (!gotsize && !mdel) { /* Didn't get size yet */
7733 if (havesize > (CK_OFF_T)-1) { /* Already have file size? */
7736 } else { /* No - must ask server */
7737 fsize = (CK_OFF_T)-1;
7739 x = ftpcmd("SIZE",s,x_csl,x_csr,ftp_vbm);
7740 if (x == REPLY_COMPLETE) {
7741 fsize = ckatofs(&ftp_reply_str[4]);
7747 if (mdel) { /* [M]DELETE */
7748 if (displa && !ftp_vbm)
7751 (ftpcmd("DELE",s,x_csl,x_csr,ftp_vbm) == REPLY_COMPLETE) ? 1 : -1;
7753 tlog(F110,"ftp mdelete",s,0);
7754 if (displa && !ftp_vbm)
7757 tlog(F110,"ftp mdelete failed:",s,0);
7763 } else if (rcvfilter) { /* [M]GET with filter */
7766 p = tmpbuf; /* Safe - no asname with filter */
7767 zzstring(rcvfilter,&p,&n);
7770 debug(F111,"ftp get rcvfilter",pn,n);
7771 #endif /* PIPESEND */
7773 if (toscreen) s2 = "-";
7774 } else if (pipesend) { /* [M]GET /COMMAND */
7777 p = tmpbuf; /* Safe - no asname with filter */
7778 zzstring(pipename,&p,&n);
7781 debug(F111,"ftp get pipename",pipename,n);
7782 if (toscreen) s2 = "-";
7783 } else { /* [M]GET with no pipes or filters */
7784 debug(F111,"ftp get s2 A",s2,x_cnv);
7786 s2 = "-"; /* (hokey convention for stdout) */
7787 } else if (!*s2) { /* No asname? */
7788 if (x_cnv) { /* If converting */
7789 nzrtol(s,tmpbuf,x_cnv,1,CKMAXPATH); /* convert */
7791 debug(F110,"ftp get nzrtol",s2,0);
7792 } else /* otherwise */
7793 s2 = s; /* use incoming file's name */
7795 debug(F110,"ftp get s2 B",s2,0);
7797 /* If local file already exists, take collision action */
7802 #endif /* PIPESEND */
7806 debug(F111,"ftp get zchki",s2,x);
7807 debug(F111,"ftp get x_fnc",s2,x_fnc);
7809 if (x > (CK_OFF_T)-1 && !restart) {
7811 char * newname = NULL;
7814 case XYFX_A: /* Append */
7817 case XYFX_R: /* Rename */
7818 case XYFX_B: /* Backup */
7819 znewn(s2,&newname); /* Make unique name */
7820 debug(F110,"ftp get znewn",newname,0);
7821 if (x_fnc == XYFX_B) { /* Backup existing file */
7822 x = zrename(s2,newname);
7823 debug(F111,"ftp get backup zrename",newname,x);
7824 } else { /* Rename incoming file */
7825 x = ckstrncpy(tmpbuf,newname,CKMAXPATH+1);
7827 debug(F111,"ftp get rename incoming",newname,x);
7830 ftscreen(SCR_EM,0,(CK_OFF_T)0,
7831 "Backup/Rename failed");
7836 case XYFX_D: /* Discard (already handled above) */
7837 case XYFX_U: /* Update (ditto) */
7838 case XYFX_M: /* Update (ditto) */
7839 case XYFX_X: /* Overwrite */
7847 debug(F111,"ftp get pn",pn,rcvfilter ? 1 : 0);
7848 #endif /* PIPESEND */
7849 if (pipesend && !toscreen)
7853 debug(F101,"ftp get x_xla","",x_xla);
7854 debug(F101,"ftp get x_csl","",x_csl);
7855 debug(F101,"ftp get x_csr","",x_csr);
7856 debug(F101,"ftp get append","",append);
7860 rc = getfile(s,s2,restart,append,pn,x_xla,x_csl,x_csr);
7864 debug(F111,"ftp get rc",s,rc);
7865 debug(F111,"ftp get ftp_timed_out",s,ftp_timed_out);
7866 debug(F111,"ftp get cancelfile",s,cancelfile);
7867 debug(F111,"ftp get cancelgroup",s,cancelgroup);
7868 debug(F111,"ftp get renaming",s,renaming);
7869 debug(F111,"ftp get moving",s,moving);
7877 if (deleting) { /* GET /DELETE (source file) */
7879 (ftpcmd("DELE",s,x_csl,x_csr,ftp_vbm) == REPLY_COMPLETE)
7881 tlog(F110, (rc > -1) ?
7882 " deleted" : " failed to delete", s, 0);
7884 if (renaming && rcv_rename && !toscreen) {
7885 char *p; /* Rename downloaded file */
7887 char tmpbuf[CKMAXPATH+1];
7891 debug(F111,"ftp get /rename",rcv_rename,0);
7892 zzstring(rcv_rename,&p,&n);
7893 debug(F111,"ftp get /rename",rcv_rename,0);
7898 rc = (zrename(s2,p) < 0) ? -1 : 1;
7899 debug(F111,"doftpget /RENAME zrename",p,rc);
7900 tlog(F110, (rc > -1) ?
7902 " failed to rename to",
7906 } else if (moving && rcv_move && !toscreen) {
7907 char *p; /* Move downloaded file */
7909 char tmpbuf[CKMAXPATH+1];
7913 debug(F111,"ftp get /move-to",rcv_move,0);
7914 zzstring(rcv_move,&p,&n);
7919 debug(F111,"ftp get /move-to",p,0);
7920 rc = (zrename(s2,p) < 0) ? -1 : 1;
7921 debug(F111,"doftpget /MOVE zrename",p,rc);
7922 tlog(F110, (rc > -1) ?
7923 " moved to" : " failed to move to", p, 0);
7925 if (pv[SND_SRN].ival > 0 && pv[SND_SRN].sval) {
7926 char * s = pv[SND_SRN].sval;
7927 char * srvrn = pv[SND_SRN].sval;
7928 char tmpbuf[CKMAXPATH+1];
7930 int y; /* Pass it thru the evaluator */
7931 extern int cmd_quoting; /* for \v(filename) */
7932 debug(F111,"ftp get srv_renam",s,1);
7937 zzstring(srvrn,&s,&y);
7941 debug(F111,"ftp get srv_renam",s,1);
7944 x = ftp_rename(s2,s);
7945 debug(F111,"ftp get ftp_rename",s2,x);
7946 tlog(F110, (x > 0) ?
7947 " renamed source file to" :
7948 " failed to rename source file to",
7963 debug(F101,"ftp get ftp_timed_out","",ftp_timed_out);
7964 if (ftp_timed_out) {
7966 ftscreen(SCR_EM,0,(CK_OFF_T)0,"GET timed out");
7968 #endif /* FTP_TIMEOUT */
7971 ftscreen(SCR_EM,0,(CK_OFF_T)0,"Fatal download error");
7978 debug(F101,"ftp get status","",status);
7979 debug(F101,"ftp get cancelgroup","",cancelgroup);
7980 debug(F101,"ftp get cancelfile","",cancelfile);
7981 debug(F101,"ftp get selected","",selected);
7982 debug(F101,"ftp get good","",good);
7986 if (selected == 0) { /* No files met selection criteria */
7987 status = 1; /* which is a kind of success. */
7988 } else if (status > 0) { /* Some files were selected */
7989 if (cancelgroup) /* but MGET was canceled */
7990 status = 0; /* so MGET failed */
7991 else if (cancelfile && good < 1) /* If file was canceled */
7992 status = 0; /* MGET failed if it got no files */
7996 debug(F101,"ftp get success","",success);
7999 pipesend = pipesave; /* Restore global pipe selection */
8000 if (fp_nml) { /* Close /NAMELIST */
8001 if (fp_nml != stdout)
8010 #endif /* COMMENT */
8011 ) { /* Download successful */
8013 t1 = gmstimer(); /* End time */
8014 sec = (CKFLOAT)((CKFLOAT)(t1 - t0) / 1000.0); /* Stats */
8015 if (!sec) sec = 0.001;
8018 sec = (t1 - t0) / 1000;
8020 #endif /* GFTIMER */
8021 tfcps = (long) (tfc / sec);
8023 lastxfer = W_FTP|W_RECV;
8027 ftscreen(success > 0 ? SCR_TC : SCR_CW, 0, (CK_OFF_T)0, "");
8029 if (f_tmpdir) { /* If we changed to download dir */
8030 zchdir((char *) savdir); /* Go back where we came from */
8033 #endif /* CK_TMPDIR */
8035 for (i = 0; i <= SND_MAX; i++) { /* Free malloc'd memory */
8039 for (i = 0; i < mgetn; i++) /* MGET list too */
8040 makestr(&(mgetlist[i]),NULL);
8042 if (cancelgroup) /* Clear temp-file stack */
8045 ftreset(); /* Undo switch effects */
8050 static struct keytab ftprmt[] = {
8052 { "cdup", XZCDU, 0 },
8053 { "cwd", XZCWD, CM_INV },
8054 { "delete", XZDEL, 0 },
8055 { "directory", XZDIR, 0 },
8056 { "exit", XZXIT, 0 },
8057 { "help", XZHLP, 0 },
8058 { "login", XZLGI, 0 },
8059 { "logout", XZLGO, 0 },
8060 { "mkdir", XZMKD, 0 },
8061 { "pwd", XZPWD, 0 },
8062 { "rename", XZREN, 0 },
8063 { "rmdir", XZRMD, 0 },
8064 { "type", XZTYP, 0 },
8067 static int nftprmt = (sizeof(ftprmt) / sizeof(struct keytab)) - 1;
8070 doftpsite() { /* Send a SITE command */
8073 int lcs = -1, rcs = -1;
8074 int save_vbm = ftp_vbm;
8079 if (lcs < 0) lcs = fcharset;
8081 if (rcs < 0) rcs = ftp_csr;
8083 #endif /* NOCSETS */
8084 if ((x = cmtxt("Command", "", &s, xxstring)) < 0)
8087 ckstrncpy(line,s,LINBUFSIZ);
8088 if (testing) printf(" ftp site \"%s\"...\n",line);
8090 ftp_vbm = !ckstrcmp("HELP",line,4,0);
8091 if ((reply = ftpcmd("SITE",line,lcs,rcs,ftp_vbm)) == REPLY_PRELIM) {
8093 reply = getreply(0,lcs,rcs,ftp_vbm,0);
8094 } while (reply == REPLY_PRELIM);
8097 return(success = (reply == REPLY_COMPLETE));
8102 dosetftppsv() { /* Passive mode */
8103 x = seton(&ftp_psv);
8104 if (x > 0) passivemode = ftp_psv;
8108 /* d o f t p r m t -- Parse and execute REMOTE commands */
8111 doftprmt(cx,who) int cx, who; { /* who == 1 for ftp, 0 for kermit */
8112 /* cx == 0 means REMOTE */
8113 /* cx != 0 is a XZxxx value */
8120 if ((x = cmkey(ftprmt,nftprmt,"","",xxstring)) < 0)
8125 case XZCDU: /* CDUP */
8126 if ((x = cmcfm()) < 0) return(x);
8127 return(doftpcdup());
8129 case XZCWD: /* RCD */
8130 if ((x = cmtxt("Remote directory", "", &s, xxstring)) < 0)
8132 ckstrncpy(line,s,LINBUFSIZ);
8134 return(doftpcwd(s,1));
8135 case XZPWD: /* RPWD */
8137 case XZDEL: /* RDEL */
8138 return(doftpget(FTP_MDE,1));
8139 case XZDIR: /* RDIR */
8140 return(doftpdir(FTP_DIR));
8141 case XZHLP: /* RHELP */
8142 return(doftpxhlp());
8143 case XZMKD: /* RMKDIR */
8145 case XZREN: /* RRENAME */
8147 case XZRMD: /* RRMDIR */
8149 case XZLGO: /* LOGOUT */
8151 case XZXIT: /* EXIT */
8154 printf("?Not usable with FTP - \"%s\"\n", atmbuf);
8159 doxftp() { /* Command parser for built-in FTP */
8164 int lcs = -1, rcs = -1;
8169 if (lcs < 0) lcs = fcharset;
8171 if (rcs < 0) rcs = ftp_csr;
8173 #endif /* NOCSETS */
8175 if (inserver) /* FTP not allowed in IKSD. */
8178 if (g_ftp_typ > -1) { /* Restore TYPE if saved */
8179 ftp_typ = g_ftp_typ;
8180 /* g_ftp_typ = -1; */
8184 We'll set the collision action locally in doftpget() based on whether
8185 ftp_fnc was ever set to a value. if not, we'll use the fncact value.
8187 if (ftp_fnc < 0) /* Inherit global collision action */
8188 ftp_fnc = fncact; /* if none specified for FTP */
8189 #endif /* COMMENT */
8191 /* Restore global verbose mode */
8199 ftp_dates &= 1; /* Undo any previous /UPDATE switch */
8201 dpyactive = 0; /* Reset global transfer-active flag */
8202 printlines = 0; /* Reset printlines */
8204 if (fp_nml) { /* Reset /NAMELIST */
8205 if (fp_nml != stdout)
8209 makestr(&ftp_nml,NULL);
8211 cmfdbi(&kw, /* First FDB - commands */
8213 "Hostname; or FTP command", /* help */
8215 "", /* addtl string data */
8216 nftpcmd, /* addtl numeric data 1: tbl size */
8217 0, /* addtl numeric data 2: none */
8218 xxstring, /* Processing function */
8219 ftpcmdtab, /* Keyword table */
8220 &fl /* Pointer to next FDB */
8222 cmfdbi(&fl, /* A host name or address */
8224 "Hostname or address", /* help */
8226 "", /* addtl string data */
8227 0, /* addtl numeric data 1 */
8228 0, /* addtl numeric data 2 */
8233 x = cmfdb(&kw); /* Parse a hostname or a keyword */
8235 printf("?ftp what? \"help ftp\" for hints\n");
8240 if (cmresult.fcode == _CMFLD) { /* If hostname */
8241 return(openftp(cmresult.sresult,0)); /* go open the connection */
8243 cx = cmresult.nresult;
8246 case FTP_ACC: /* ACCOUNT */
8247 if ((x = cmtxt("Remote account", "", &s, xxstring)) < 0)
8250 makestr(&ftp_acc,s);
8252 printf(" ftp account: \"%s\"\n",ftp_acc);
8253 success = (ftpcmd("ACCT",ftp_acc,-1,-1,ftp_vbm) == REPLY_COMPLETE);
8256 case FTP_GUP: /* Go UP */
8257 if ((x = cmcfm()) < 0) return(x);
8259 if (testing) printf(" ftp cd: \"(up)\"\n");
8260 return(success = doftpcdup());
8262 case FTP_CWD: /* CD */
8263 if ((x = cmtxt("Remote directory", "", &s, xxstring)) < 0)
8266 ckstrncpy(line,s,LINBUFSIZ);
8268 printf(" ftp cd: \"%s\"\n", line);
8269 return(success = doftpcwd(line,1));
8271 case FTP_CHM: /* CHMOD */
8272 if ((x = cmfld("Permissions or protection code","",&s,xxstring)) < 0)
8274 ckstrncpy(tmpbuf,s,TMPBUFSIZ);
8275 if ((x = cmtxt("Remote filename", "", &s, xxstring)) < 0)
8278 ckmakmsg(ftpcmdbuf,FTP_BUFSIZ,tmpbuf," ",s,NULL);
8280 printf(" ftp chmod: %s\n",ftpcmdbuf);
8282 (ftpcmd("SITE CHMOD",ftpcmdbuf,lcs,rcs,ftp_vbm) == REPLY_COMPLETE);
8285 case FTP_CLS: /* CLOSE FTP connection */
8286 if ((y = cmcfm()) < 0)
8290 printf(" ftp closing...\n");
8292 return(success = 1);
8294 case FTP_DIR: /* DIRECTORY of remote files */
8296 return(doftpdir(cx));
8298 case FTP_GET: /* GET a remote file */
8299 case FTP_RGE: /* REGET */
8300 case FTP_MGE: /* MGET */
8301 case FTP_MDE: /* MDELETE */
8302 return(doftpget(cx,1));
8304 case FTP_IDL: /* IDLE */
8305 if ((x = cmnum("Number of seconds","-1",10,&z,xxstring)) < 0)
8307 if ((y = cmcfm()) < 0)
8310 if (z < 0) { /* Display idle timeout */
8312 printf(" ftp query idle timeout...\n");
8313 success = (ftpcmd("SITE IDLE",NULL,0,0,1) == REPLY_COMPLETE);
8314 } else { /* Set idle timeout */
8316 printf(" ftp idle timeout set: %d...\n",z);
8318 (ftpcmd("SITE IDLE",ckitoa(z),0,0,1) == REPLY_COMPLETE);
8322 case FTP_MKD: /* MKDIR */
8325 case FTP_MOD: /* MODTIME */
8326 if ((x = cmtxt("Remote filename", "", &s, xxstring)) < 0)
8329 ckstrncpy(line,s,LINBUFSIZ);
8331 printf(" ftp modtime \"%s\"...\n",line);
8333 if (ftpcmd("MDTM",line,lcs,rcs,ftp_vbm) == REPLY_COMPLETE) {
8341 bzero((char *)&tmremote, sizeof(struct tm));
8343 while ((c = *s++)) {
8350 if (sscanf(s, "%04d%02d%02d%02d%02d%02d",
8358 printf(" %s %04d-%02d-%02d %02d:%02d:%02d GMT\n",
8375 case FTP_OPN: /* OPEN connection */
8377 x = cmfld("IP hostname or address","",&s,xxstring);
8382 ckstrncpy(line,s,LINBUFSIZ);
8384 return(openftp(s,0));
8386 { /* OPEN connection */
8387 char name[TTNAMLEN+1], *p;
8389 extern char ttname[];
8390 if (network) /* If we have a current connection */
8391 ckstrncpy(name,ttname,LINBUFSIZ); /* get the host name */
8393 *name = '\0'; /* as default host */
8394 for (p = name; *p; p++) /* Remove ":service" from end. */
8395 if (*p == ':') { *p = '\0'; break; }
8397 x = cmfld("IP hostname or address",name,&s,xxstring);
8399 cmfdbi(&kw, /* First FDB - commands */
8401 "Hostname or switch", /* help */
8403 "", /* addtl string data */
8404 ntlstab, /* addtl numeric data 1: tbl size */
8405 0, /* addtl numeric data 2: none */
8406 xxstring, /* Processing function */
8407 tlstab, /* Keyword table */
8408 &fl /* Pointer to next FDB */
8410 cmfdbi(&fl, /* A host name or address */
8412 "Hostname or address", /* help */
8414 "", /* addtl string data */
8415 0, /* addtl numeric data 1 */
8416 0, /* addtl numeric data 2 */
8423 x = cmfdb(&kw); /* Parse a hostname or a keyword */
8425 printf("?ftp open what? \"help ftp\" for hints\n");
8430 if (cmresult.fcode == _CMFLD) { /* Hostname */
8431 s = cmresult.sresult;
8433 } else if (cmresult.nresult == OPN_TLS) {
8437 #endif /* USETLSTAB */
8442 ckstrncpy(line,s,LINBUFSIZ);
8444 return(openftp(s,usetls));
8446 #endif /* COMMENT */
8448 case FTP_PUT: /* PUT */
8449 case FTP_MPU: /* MPUT */
8450 case FTP_APP: /* APPEND */
8451 case FTP_REP: /* REPUT */
8452 return(doftpput(cx,1));
8454 case FTP_PWD: /* PWD */
8456 if (x > -1) success = x;
8459 case FTP_REN: /* RENAME */
8462 case FTP_RES: /* RESET */
8465 case FTP_HLP: /* (remote) HELP */
8466 return(doftpxhlp());
8468 case FTP_RMD: /* RMDIR */
8471 case FTP_STA: /* STATUS */
8472 if ((x = cmtxt("Command", "", &s, xxstring)) < 0)
8475 ckstrncpy(line,s,LINBUFSIZ);
8476 if (testing) printf(" ftp status \"%s\"...\n",line);
8477 success = (ftpcmd("STAT",line,lcs,rcs,1) == REPLY_COMPLETE);
8480 case FTP_SIT: { /* SITE */
8481 return(doftpsite());
8484 case FTP_SIZ: /* (ask for) SIZE */
8485 if ((x = cmtxt("Remote filename", "", &s, xxstring)) < 0)
8488 ckstrncpy(line,s,LINBUFSIZ);
8490 printf(" ftp size \"%s\"...\n",line);
8491 success = (ftpcmd("SIZE",line,lcs,rcs,1) == REPLY_COMPLETE);
8496 case FTP_SYS: /* Ask for server's SYSTEM type */
8497 if ((x = cmcfm()) < 0) return(x);
8500 printf(" ftp system...\n");
8501 success = (ftpcmd("SYST",NULL,0,0,1) == REPLY_COMPLETE);
8504 case FTP_UMA: /* Set/query UMASK */
8505 if ((x = cmfld("Umask to set or nothing to query","",&s,xxstring)) < 0)
8508 ckstrncpy(tmpbuf,s,TMPBUFSIZ);
8509 if ((x = cmcfm()) < 0) return(x);
8513 printf(" ftp umask \"%s\"...\n",tmpbuf);
8515 printf(" ftp query umask...\n");
8517 success = ftp_umask(tmpbuf);
8524 if ((x = cmtxt("FTP protocol command", "", &s, xxstring)) < 0)
8527 success = (ftpcmd(s,NULL,0,0,ftp_vbm) == REPLY_COMPLETE);
8530 case FTP_TYP: /* Type */
8531 if ((x = cmkey(ftptyp,nftptyp,"","",xxstring)) < 0)
8533 if ((y = cmcfm()) < 0) return(y);
8537 tenex = (ftp_typ == FTT_TEN);
8538 changetype(ftp_typ,ftp_vbm);
8541 case FTP_CHK: /* Check if remote file(s) exist(s) */
8542 if ((x = cmtxt("remote filename", "", &s, xxstring)) < 0)
8545 success = remote_files(1,(CHAR *)s,(CHAR *)s,0) ? 1 : 0;
8548 case FTP_FEA: /* RFC2389 */
8549 if ((y = cmcfm()) < 0)
8552 success = (ftpcmd("FEAT",NULL,0,0,1) == REPLY_COMPLETE);
8554 if (sfttab[0] > 0) {
8555 ftp_aut = sfttab[SFT_AUTH];
8556 sizeok = sfttab[SFT_SIZE];
8557 mdtmok = sfttab[SFT_MDTM];
8558 mlstok = sfttab[SFT_MLST];
8563 case FTP_OPT: /* RFC2389 */
8564 /* Perhaps this should be a keyword list... */
8565 if ((x = cmfld("FTP command","",&s,xxstring)) < 0)
8568 ckstrncpy(line,s,LINBUFSIZ);
8569 if ((x = cmtxt("Options for this command", "", &s, xxstring)) < 0)
8571 success = (ftpcmd("OPTS",line,lcs,rcs,ftp_vbm) == REPLY_COMPLETE);
8574 case FTP_ENA: /* FTP ENABLE */
8575 case FTP_DIS: /* FTP DISABLE */
8576 if ((x = cmkey(ftpenatab,nftpena,"","",xxstring)) < 0)
8578 if ((y = cmcfm()) < 0) return(y);
8580 case ENA_AUTH: /* OK to use autoauthentication */
8581 ftp_aut = (cx == FTP_ENA) ? 1 : 0;
8582 sfttab[SFT_AUTH] = ftp_aut;
8584 case ENA_FEAT: /* OK to send FEAT command */
8585 featok = (cx == FTP_ENA) ? 1 : 0;
8587 case ENA_MLST: /* OK to use MLST/MLSD */
8588 mlstok = (cx == FTP_ENA) ? 1 : 0;
8589 sfttab[SFT_MLST] = mlstok;
8591 case ENA_MDTM: /* OK to use MDTM */
8592 mdtmok = (cx == FTP_ENA) ? 1 : 0;
8593 sfttab[SFT_MDTM] = mdtmok;
8595 case ENA_SIZE: /* OK to use SIZE */
8596 sizeok = (cx == FTP_ENA) ? 1 : 0;
8597 sfttab[SFT_SIZE] = sizeok;
8600 return(success = 1);
8609 case FPL_CLR: return("clear");
8610 case FPL_PRV: return("private");
8611 case FPL_SAF: return("safe");
8612 case 0: return("(not set)");
8613 default: return("(unknown)");
8618 shoftp(brief) int brief; {
8622 if (g_ftp_typ > -1) { /* Restore TYPE if saved */
8623 ftp_typ = g_ftp_typ;
8624 /* g_ftp_typ = -1; */
8627 printf("FTP connection: %s\n",connected ?
8634 printf("FTP server type: %s\n",
8635 ftp_srvtyp[0] ? ftp_srvtyp : "(unknown)");
8638 printf("Logged in as: %s\n",
8639 strval(ftp_logname,"(unknown)"));
8641 printf("Not logged in\n");
8643 if (brief) return(0);
8645 printf("\nSET FTP values:\n\n");
8648 printf(" ftp anonymous-password: %s\n",
8649 ftp_apw ? ftp_apw : "(default)"
8651 printf(" ftp auto-login: %s\n",showoff(ftp_log));
8652 printf(" ftp auto-authentication: %s\n",showoff(ftp_aut));
8654 case FTT_ASC: s = "text"; break;
8655 case FTT_BIN: s = "binary"; break;
8656 case FTT_TEN: s = "tenex"; break;
8659 printf(" ftp timeout: %ld\n",ftp_timeout);
8660 #endif /* FTP_TIMEOUT */
8661 printf(" ftp type: %s\n",s);
8662 printf(" ftp get-filetype-switching: %s\n",showoff(get_auto));
8663 printf(" ftp dates: %s\n",showoff(ftp_dates));
8664 printf(" ftp error-action: %s\n",ftp_err ? "quit":"proceed");
8665 printf(" ftp filenames: %s\n",
8666 ftp_cnv == CNV_AUTO ? "auto" : (ftp_cnv ? "converted" : "literal")
8668 printf(" ftp debug %s\n",showoff(ftp_deb));
8670 printf(" ftp passive-mode: %s\n",showoff(ftp_psv));
8671 printf(" ftp permissions: %s\n",showooa(ftp_prm));
8672 printf(" ftp verbose-mode: %s\n",showoff(ftp_vbx));
8673 printf(" ftp send-port-commands: %s\n",showoff(ftp_psv));
8674 printf(" ftp unique-server-names: %s\n",showoff(ftp_usn));
8676 /* See note in doxftp() */
8679 #endif /* COMMENT */
8680 printf(" ftp collision: %s\n",
8681 fncnam[ftp_fnc > -1 ? ftp_fnc : fncact]);
8682 printf(" ftp server-time-offset: %s\n",
8683 fts_sto ? fts_sto : "(none)");
8687 printf(" ftp character-set-translation: %s\n",showoff(ftp_xla));
8688 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8690 printf(" ftp server-character-set: %s\n",fcsinfo[ftp_csr].keyword);
8691 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8693 printf(" file character-set: %s\n",fcsinfo[fcharset].keyword);
8694 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8695 #endif /* NOCSETS */
8701 case XYFD_N: s = "none"; break;
8702 case XYFD_R: s = "serial"; break;
8703 case XYFD_C: s = "fullscreen"; break;
8704 case XYFD_S: s = "crt"; break;
8705 case XYFD_B: s = "brief"; break;
8707 printf(" ftp display: %s\n",s);
8708 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8710 if (mlstok || featok || mdtmok || sizeok || ftp_aut) {
8711 printf(" enabled: ");
8712 if (ftp_aut) printf(" AUTH");
8713 if (featok) printf(" FEAT");
8714 if (mdtmok) printf(" MDTM");
8715 if (mlstok) printf(" MLST");
8716 if (sizeok) printf(" SIZE");
8718 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8720 if (!mlstok || !featok || !mdtmok || !sizeok || !ftp_aut) {
8721 printf(" disabled: ");
8722 if (!ftp_aut) printf(" AUTH");
8723 if (!featok) printf(" FEAT");
8724 if (!mdtmok) printf(" MDTM");
8725 if (!mlstok) printf(" MLST");
8726 if (!sizeok) printf(" SIZE");
8728 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8731 case 0: s = "kermit"; break;
8732 case 1: s = "ftp"; break;
8733 case 2: s = "auto"; break;
8736 printf(" get-put-remote: %s\n",s);
8737 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8740 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8743 printf("Available security methods: ");
8746 #endif /* FTP_GSSAPI */
8748 printf("Kerberos4 ");
8749 #endif /* FTP_KRB4 */
8752 #endif /* FTP_SRP */
8755 #endif /* FTP_SSL */
8759 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8760 printf(" ftp authtype: %s\n",strval(auth_type,NULL));
8761 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8762 printf(" ftp auto-encryption: %s\n",showoff(ftp_cry));
8763 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8764 printf(" ftp credential-forwarding: %s\n",showoff(ftp_cfw));
8765 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8766 printf(" ftp command-protection-level: %s\n",shopl(ftp_cpl));
8767 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8768 printf(" ftp data-protection-level: %s\n",shopl(ftp_dpl));
8769 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8770 printf(" ftp secure proxy: %s\n",shopl(ssl_ftp_proxy));
8771 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8773 printf("Available security methods: (none)\n");
8774 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8775 #endif /* FTP_SECURITY */
8777 if (n <= cmd_rows - 3)
8784 /* FTP HELP text strings */
8786 static char * fhs_ftp[] = {
8787 "Syntax: FTP subcommand [ operands ]",
8788 " Makes an FTP connection, or sends a command to the FTP server.",
8789 " To see a list of available FTP subcommands, type \"ftp ?\".",
8790 " and then use HELP FTP xxx to get help about subcommand xxx.",
8791 " Also see HELP SET FTP, HELP SET GET-PUT-REMOTE, and HELP FIREWALL.",
8795 static char * fhs_acc[] = { /* ACCOUNT */
8796 "Syntax: FTP ACCOUNT text",
8797 " Sends an account designator to an FTP server that needs one.",
8798 " Most FTP servers do not use accounts; some use them for other",
8799 " other purposes, such as disk-access passwords.",
8802 static char * fhs_app[] = { /* APPEND */
8803 "Syntax: FTP APPEND filname",
8804 " Equivalent to [ FTP ] PUT /APPEND. See HELP FTP PUT.",
8807 static char * fhs_cls[] = { /* BYE, CLOSE */
8808 "Syntax: [ FTP ] BYE",
8809 " Logs out from the FTP server and closes the FTP connection.",
8810 " Also see HELP SET GET-PUT-REMOTE. Synonym: [ FTP ] CLOSE.",
8813 static char * fhs_cwd[] = { /* CD, CWD */
8814 "Syntax: [ FTP ] CD directory",
8815 " Asks the FTP server to change to the given directory.",
8816 " Also see HELP SET GET-PUT-REMOTE. Synonyms: [ FTP ] CWD, RCD, RCWD.",
8819 static char * fhs_gup[] = { /* CDUP, UP */
8821 " Asks the FTP server to change to the parent directory of its current",
8822 " directory. Also see HELP SET GET-PUT-REMOTE. Synonym: FTP UP.",
8825 static char * fhs_chm[] = { /* CHMOD */
8826 "Syntax: FTP CHMOD filename permissions",
8827 " Asks the FTP server to change the permissions, protection, or mode of",
8828 " the given file. The given permissions must be in the syntax of the",
8829 " the server's file system, e.g. an octal number for UNIX. Also see",
8830 " FTP PUT /PERMISSIONS",
8833 static char * fhs_mde[] = { /* DELETE */
8834 "Syntax: FTP DELETE [ switches ] filespec",
8835 " Asks the FTP server to delete the given file or files.",
8836 " Synonym: MDELETE (Kermit makes no distinction between single and",
8837 " multiple file deletion). Optional switches:",
8839 " /ERROR-ACTION:{PROCEED,QUIT}",
8841 " /FILENAMES:{AUTO,CONVERTED,LITERAL}",
8842 " /LARGER-THAN:number",
8845 #endif /* UNIXOROSK */
8848 " /RECURSIVE (depends on server)",
8850 #endif /* RECURSIVE */
8851 " /SMALLER-THAN:number",
8854 static char * fhs_dir[] = { /* DIRECTORY */
8855 "Syntax: FTP DIRECTORY [ filespec ]",
8856 " Asks the server to send a directory listing of the files that match",
8857 " the given filespec, or if none is given, all the files in its current",
8858 " directory. The filespec, including any wildcards, must be in the",
8859 " syntax of the server's file system. Also see HELP SET GET-PUT-REMOTE.",
8860 " Synonym: RDIRECTORY.",
8863 static char * fhs_vdi[] = { /* VDIRECTORY */
8864 "Syntax: FTP VDIRECTORY [ filespec ]",
8865 " Asks the server to send a directory listing of the files that match",
8866 " the given filespec, or if none is given, all the files in its current",
8867 " directory. VDIRECTORY is needed for getting verbose directory",
8868 " listings from certain FTP servers, such as on TOPS-20. Try it if",
8869 " FTP DIRECTORY lists only filenames without details.",
8872 static char * fhs_fea[] = { /* FEATURES */
8873 "Syntax: FTP FEATURES",
8874 " Asks the FTP server to list its special features. Most FTP servers",
8875 " do not recognize this command.",
8878 static char * fhs_mge[] = { /* MGET */
8879 "Syntax: [ FTP ] MGET [ options ] filespec [ filespec [ filespec ... ] ]",
8880 " Download a single file or multiple files. Asks the FTP server to send",
8881 " the given file or files. Also see FTP GET. Optional switches:",
8884 " Name under which to store incoming file.",
8885 " Pattern required for for multiple files.",
8886 " /BINARY", /* /IMAGE */
8887 " Force binary mode. Synonym: /IMAGE.",
8888 " /COLLISION:{BACKUP,RENAME,UPDATE,DISCARD,APPEND,OVERWRITE}",
8889 " What to do if an incoming file has the same name as an existing file.",
8893 " Specifies that the as-name is a command to which the incoming file",
8894 " is to be piped as standard input.",
8895 #endif /* PUTPIPE */
8899 " Download only those files whose modification date-times differ from",
8900 " those of the corresponding local files, or that do not already",
8901 " exist on the local computer.",
8902 #endif /* DOUPDATE */
8905 " Specifies that each file is to be deleted from the server after,",
8906 " and only if, it is successfully downloaded.",
8907 " /ERROR-ACTION:{PROCEED,QUIT}",
8908 " When downloading a group of files, what to do upon failure to",
8909 " transfer a file: quit or proceed to the next one.",
8911 " Exception list: don't download any files that match this pattern.",
8912 " See HELP WILDCARD for pattern syntax.",
8913 " /FILENAMES:{AUTOMATIC,CONVERTED,LITERAL}",
8914 " Whether to convert incoming filenames to local syntax.",
8918 " Pass incoming files through the given command.",
8920 #endif /* PIPESEND */
8921 " /LARGER-THAN:number",
8922 " Only download files that are larger than the given number of bytes.",
8923 " /LISTFILE:filename",
8924 " Obtain the list of files to download from the given file.",
8926 " /LOCAL-CHARACTER-SET:name",
8927 " When downloading in text mode and character-set conversion is",
8928 " desired, this specifies the target set.",
8929 #endif /* NOCSETS */
8931 " Specifies a pattern to be used to select filenames locally from the",
8934 " Forces sending of MLSD (rather than NLST) to get the file list.",
8936 " /MOVE-TO:directory",
8937 " Each file that is downloaded is to be moved to the given local",
8938 " directory immediately after, and only if, it has been received",
8940 #endif /* CK_TMPDIR */
8941 " /NAMELIST:filename",
8942 " Instead of downloading the files, stores the list of files that",
8943 " would be downloaded in the given local file, one filename per line.",
8945 " Forces sending of NLST (rather than MLSD) to get the file list.",
8947 " Don't download any files whose names end with .~<number>~.",
8949 " Don't download any files whose names begin with period (.).",
8951 " Suppress the file-transfer display.",
8953 " /RECOVER", /* /RESTART */
8954 " Resume a download that was previously interrupted from the point of",
8955 " failure. Works only in binary mode. Not supported by all servers.",
8956 " Synonym: /RESTART.",
8957 #endif /* FTP_RESTART */
8959 " /RECURSIVE", /* /SUBDIRECTORIES */
8960 " Create subdirectories automatically if the server sends files",
8961 " recursively and includes pathnames (most don't).",
8962 #endif /* RECURSIVE */
8964 " Each file that is downloaded is to be renamed as indicated just,",
8965 " after, and only if, it has arrived successfully.",
8967 " /SERVER-CHARACTER-SET:name",
8968 " When downloading in text mode and character-set conversion is desired"
8969 , " this specifies the original file's character set on the server.",
8970 #endif /* NOCSETS */
8971 " /SERVER-RENAME:text",
8972 " Each server source file is to be renamed on the server as indicated",
8973 " immediately after, but only if, it has arrived successfully.",
8974 " /SMALLER-THAN:number",
8975 " Download only those files smaller than the given number of bytes.",
8976 " /TEXT", /* /ASCII */
8977 " Force text mode. Synonym: /ASCII.",
8979 " Force TENEX (TOPS-20) mode (see HELP SET FTP TYPE).",
8982 " When downloading in text mode, do not convert chracter-sets.",
8983 #endif /* NOCSETS */
8985 " The downloaded file is to be displayed on the screen.",
8988 " Equivalent to /COLLISION:UPDATE. Download only those files that are",
8989 " newer than than their local counterparts, or that do not exist on",
8990 " the local computer.",
8991 #endif /* DOUPDATE */
8994 static char * fhs_hlp[] = { /* HELP */
8995 "Syntax: FTP HELP [ command [ subcommand... ] ]",
8996 " Asks the FTP server for help about the given command. First use",
8997 " FTP HELP by itself to get a list of commands, then use HELP FTP xxx",
8998 " to get help for command \"xxx\". Synonyms: REMOTE HELP, RHELP.",
9001 static char * fhs_idl[] = { /* IDLE */
9002 "Syntax: FTP IDLE [ number ]",
9003 " If given without a number, this asks the FTP server to tell its",
9004 " current idle-time limit. If given with a number, it asks the server",
9005 " to change its idle-time limit to the given number of seconds.",
9008 static char * fhs_usr[] = { /* USER, LOGIN */
9009 "Syntax: FTP USER username [ password [ account ] ]",
9010 " Log in to the FTP server. To be used when connected but not yet",
9011 " logged in, e.g. when SET FTP AUTOLOGIN is OFF or autologin failed.",
9012 " If you omit the password, and one is required by the server, you are",
9013 " prompted for it. If you omit the account, no account is sent.",
9014 " Synonym: FTP LOGIN.",
9017 static char * fhs_get[] = { /* GET */
9018 "Syntax: [ FTP ] GET [ options ] filename [ as-name ]",
9019 " Download a single file. Asks the FTP server to send the given file.",
9020 " The optional as-name is the name to store it under when it arrives;",
9021 " if omitted, the file is stored with the name it arrived with, as",
9022 " modified according to the FTP FILENAMES setting or /FILENAMES: switch",
9023 " value. Aside from the file list and as-name, syntax and options are",
9024 " the same as for FTP MGET, which is used for downloading multiple files."
9027 static char * fhs_mkd[] = { /* MKDIR */
9028 "Syntax: FTP MKDIR directory",
9029 " Asks the FTP server to create a directory with the given name,",
9030 " which must be in the syntax of the server's file system. Synonyms:",
9031 " REMOTE MKDIR, RMKDIR.",
9034 static char * fhs_mod[] = { /* MODTIME */
9035 "Syntax: FTP MODTIME filename",
9036 " Asks the FTP server to send the modification time of the given file,",
9037 " to be displayed on the screen. The date-time format is all numeric:",
9038 " yyyymmddhhmmssxxx... (where xxx... is 0 or more digits indicating",
9039 " fractions of seconds).",
9042 static char * fhs_mpu[] = { /* MPUT */
9043 "Syntax: [ FTP ] MPUT [ switches ] filespec [ filespec [ filespec ... ] ]",
9044 " Uploads files. Sends the given file or files to the FTP server.",
9045 " Also see FTP PUT. Optional switches are:",
9047 " /AFTER:date-time",
9048 " Uploads only those files newer than the given date-time.",
9049 " HELP DATE for info about date-time formats. Synonym: /SINCE.",
9051 " /ARRAY:array-designator",
9052 " Tells Kermit to upload the contents of the given array, rather than",
9054 #endif /* PUTARRAY */
9056 " Name under which to send files.",
9057 " Pattern required for for multiple files.",
9058 " /BEFORE:date-time",
9059 " Upload only those files older than the given date-time.",
9061 " Force binary mode. Synonym: /IMAGE.",
9064 " Specifies that the filespec is a command whose standard output is",
9066 #endif /* PUTPIPE */
9071 " Upload only those files whose modification date-times differ from",
9072 " those on the server, or that don't exist on the server at all.",
9073 #endif /* DOUPDATE */
9074 #endif /* COMMENT */
9077 " Specifies that each source file is to be deleted after, and only if,",
9078 " it is successfully uploaded.",
9080 " Include files whose names begin with period (.).",
9081 " /ERROR-ACTION:{PROCEED,QUIT}",
9082 " When uploading a group of files, what to do upon failure to",
9083 " transfer a file: quit or proceed to the next one.",
9085 " Exception list: don't upload any files that match this pattern.",
9086 " See HELP WILDCARD for pattern syntax.",
9087 " /FILENAMES:{AUTOMATIC,CONVERTED,LITERAL}",
9088 " Whether to convert outbound filenames to common syntax.",
9092 " Pass outbound files through the given command.",
9094 #endif /* PIPESEND */
9097 " Send files that are pointed to by symbolic links.",
9099 " Skip over symbolic links (default).",
9100 #endif /* CKSYMLINK */
9101 " /LARGER-THAN:number",
9102 " Only upload files that are larger than the given number of bytes.",
9103 " /LISTFILE:filename",
9104 " Obtain the list of files to upload from the given file.",
9106 " /LOCAL-CHARACTER-SET:name",
9107 " When uploading in text mode and character-set conversion is",
9108 " desired, this specifies the source-file character set.",
9109 #endif /* NOCSETS */
9111 " /MOVE-TO:directory",
9112 " Each source file that is uploaded is to be moved to the given local",
9113 " directory when, and only if, the transfer is successful.",
9114 #endif /* CK_TMPDIR */
9116 " Don't upload any files whose names end with .~<number>~.",
9119 " Don't upload any files whose names begin with period (.).",
9120 #endif /* UNIXOROSK */
9121 " /NOT-AFTER:date-time",
9122 " Upload only files that are not newer than the given date-time",
9123 " /NOT-BEFORE:date-time",
9124 " Upload only files that are not older than the given date-time",
9127 " Ask the server to set the permissions of each file it receives",
9128 " according to the source file's permissions.",
9131 " Suppress the file-transfer display.",
9134 " Resume an upload that was previously interrupted from the point of",
9135 " failure. Synonym: /RESTART.",
9136 #endif /* FTP_RESTART */
9139 " Send files from the given directory and all the directories beneath",
9140 " it. Synonym: /SUBDIRECTORIES.",
9141 #endif /* RECURSIVE */
9143 " Each source file that is uploaded is to be renamed on the local",
9144 " local computer as indicated when and only if, the transfer completes",
9147 " /SERVER-CHARACTER-SET:name",
9148 " When uploading in text mode and character-set conversion is desired,",
9149 " this specifies the character set to which the file should be",
9150 " converted for storage on the server.",
9151 #endif /* NOCSETS */
9152 " /SERVER-RENAME:text",
9153 " Each file that is uploaded is to be renamed as indicated on the",
9154 " server after, and only if, if arrives successfully.",
9156 " Show which files would be sent without actually sending them.",
9157 " /SMALLER-THAN:number",
9158 " Upload only those files smaller than the given number of bytes.",
9160 " Force text mode. Synonym: /ASCII.",
9162 " Force TENEX (TOPS-20) mode (see HELP SET FTP TYPE).",
9165 " When uploading in text mode, do not convert chracter-sets.",
9166 #endif /* NOCSETS */
9167 " /TYPE:{TEXT,BINARY}",
9168 " Upload only files of the given type.",
9171 " If a file of the same name exists on the server, upload only if",
9172 " the local file is newer.",
9173 #endif /* DOUPDATE */
9174 " /UNIQUE-SERVER-NAMES",
9175 " Ask the server to compute new names for any incoming file that has",
9176 " the same name as an existing file.",
9179 static char * fhs_opn[] = { /* OPEN */
9181 "Syntax: FTP [ OPEN ] [ { /SSL, /TLS } ] hostname [ port ] [ switches ]",
9182 " Opens a connection to the FTP server on the given host. The default",
9183 " TCP port is 21 (990 if SSL/TLS is used), but a different port number",
9184 " can be supplied if necessary. Optional switches are:",
9186 "Syntax: FTP [ OPEN ] hostname [ port ] [ switches ]",
9187 " Opens a connection to the FTP server on the given host. The default",
9188 " TCP port is 21, but a different port number can be supplied if",
9189 " necessary. Optional switches are:",
9193 " Logs you in anonymously.",
9195 " Supplies the given text as your username.",
9197 " Supplies the given text as your password. If you include a username",
9198 " but omit this switch and the server requires a password, you are",
9199 " prompted for it.",
9201 " Supplies the given text as your account, if required by the server.",
9203 " Forces an active (rather than passive) connection.",
9205 " Forces a passive (rather than active) connection.",
9207 " Inhibits sending initial REST, STRU, and MODE commands, which are",
9208 " well-known standard commands, but to which some servers react badly.",
9210 " Inhibits autologin for this connection only.",
9213 static char * fhs_opt[] = { /* OPTS, OPTIONS */
9214 "Syntax: FTP OPTIONS",
9215 " Asks the FTP server to list its current options. Advanced, new,",
9216 " not supported by most FTP servers.",
9219 static char * fhs_put[] = { /* PUT, SEND */
9220 "Syntax: [ FTP ] PUT [ switches ] filespec [ as-name ]",
9221 " Like FTP MPUT, but only one filespec is allowed, and if it is followed",
9222 " by an additional field, this is interpreted as the name under which",
9223 " to send the file or files. See HELP FTP MPUT.",
9226 static char * fhs_reput[] = { /* REPUT, RESEND */
9227 "Syntax: [ FTP ] REPUT [ switches ] filespec [ as-name ]",
9228 " Synonym for FTP PUT /RECOVER. Recovers an interrupted binary-mode",
9229 " upload from the point of failure if the FTP server supports recovery.",
9230 " Synonym: [ FTP ] RESEND. For details see HELP FTP MPUT.",
9233 static char * fhs_pwd[] = { /* PWD */
9235 " Asks the FTP server to reveal its current working directory.",
9236 " Synonyms: REMOTE PWD, RPWD.",
9239 static char * fhs_quo[] = { /* QUOTE */
9240 "Syntax: FTP QUOTE text",
9241 " Sends an FTP protocol command to the FTP server. Use this command",
9242 " for sending commands that Kermit might not support.",
9245 static char * fhs_rge[] = { /* REGET */
9246 "Syntax: FTP REGET",
9247 " Synonym for FTP GET /RECOVER.",
9250 static char * fhs_ren[] = { /* RENAME */
9251 "Syntax: FTP RENAME name1 name1",
9252 " Asks the FTP server to change the name of the file whose name is name1",
9253 " and which resides in the FTP server's file system, to name2. Works",
9254 " only for single files; wildcards are not accepted.",
9257 static char * fhs_res[] = { /* RESET */
9258 "Syntax: FTP RESET",
9259 " Asks the server to log out your session, terminating your access",
9260 " rights, without closing the connection.",
9263 static char * fhs_rmd[] = { /* RMDIR */
9264 "Syntax: FTP RMDIR directory",
9265 " Asks the FTP server to remove the directory whose name is given.",
9266 " This usually requires the directory to be empty. Synonyms: REMOTE",
9270 static char * fhs_sit[] = { /* SITE */
9271 "Syntax: FTP SITE text",
9272 " Sends a site-specific command to the FTP server.",
9275 static char * fhs_siz[] = { /* SIZE */
9276 "Syntax: FTP SIZE filename",
9277 " Asks the FTP server to send a numeric string representing the size",
9278 " of the given file.",
9281 static char * fhs_sta[] = { /* STATUS */
9282 "Syntax: FTP STATUS [ filename ]",
9283 " Asks the FTP server to report its status. If a filename is given,",
9284 " the FTP server should report details about the file.",
9287 static char * fhs_sys[] = { /* SYSTEM */
9288 "Syntax: FTP SYSTEM",
9289 " Asks the FTP server to report its operating system type.",
9292 static char * fhs_typ[] = { /* TYPE */
9293 "Syntax: FTP TYPE { TEXT, BINARY, TENEX }",
9294 " Puts the client and server in the indicated transfer mode.",
9295 " ASCII is a synonym for TEXT. TENEX is used only for uploading 8-bit",
9296 " binary files to a 36-bit platforms such as TENEX or TOPS-20 and/or",
9297 " downloading files from TENEX or TOPS-20 that have been uploaded in",
9301 static char * fhs_uma[] = { /* UMASK */
9302 "Syntax: FTP UMASK number",
9303 " Asks the FTP server to set its file creation mode mask. Applies",
9304 " only (or mainly) to UNIX-based FTP servers.",
9307 static char * fhs_chk[] = { /* CHECK */
9308 "Syntax: FTP CHECK remote-filespec",
9309 " Asks the FTP server if the given file or files exist. If the",
9310 " remote-filespec contains wildcards, this command fails if no server",
9311 " files match, and succeeds if at least one file matches. If the",
9312 " remote-filespec does not contain wildcards, this command succeeds if",
9313 " the given file exists and fails if it does not.",
9316 static char * fhs_ena[] = { /* ENABLE */
9317 "Syntax: FTP ENABLE { AUTH, FEAT, MDTM, MLST, SIZE }",
9318 " Enables the use of the given FTP protocol command in case it has been",
9319 " disabled (but this is no guarantee that the FTP server understands it)."
9321 " Use SHOW FTP to see which of these commands is enabled and disabled.",
9322 " Also see FTP DISABLE.",
9325 static char * fhs_dis[] = { /* DISABLE */
9326 "Syntax: FTP DISABLE { AUTH, FEAT, MDTM, MLST, SIZE }",
9327 " Disables the use of the given FTP protocol command.",
9328 " Also see FTP ENABLE.",
9337 if ((cx = cmkey(ftpcmdtab,nftpcmd,"","",xxstring)) < 0)
9340 if ((x = cmcfm()) < 0)
9344 printf("Sorry, no help available\n");
9348 return(hmsga(fhs_ftp));
9349 case FTP_ACC: /* ACCOUNT */
9350 return(hmsga(fhs_acc));
9351 case FTP_APP: /* APPEND */
9352 return(hmsga(fhs_app));
9353 case FTP_CLS: /* BYE, CLOSE */
9354 return(hmsga(fhs_cls));
9355 case FTP_CWD: /* CD, CWD */
9356 return(hmsga(fhs_cwd));
9357 case FTP_GUP: /* CDUP, UP */
9358 return(hmsga(fhs_gup));
9359 case FTP_CHM: /* CHMOD */
9360 return(hmsga(fhs_chm));
9361 case FTP_MDE: /* DELETE, MDELETE */
9362 return(hmsga(fhs_mde));
9363 case FTP_DIR: /* DIRECTORY */
9364 return(hmsga(fhs_dir));
9365 case FTP_VDI: /* VDIRECTORY */
9366 return(hmsga(fhs_vdi));
9367 case FTP_FEA: /* FEATURES */
9368 return(hmsga(fhs_fea));
9369 case FTP_GET: /* GET */
9370 return(hmsga(fhs_get));
9371 case FTP_HLP: /* HELP */
9372 return(hmsga(fhs_hlp));
9373 case FTP_IDL: /* IDLE */
9374 return(hmsga(fhs_idl));
9375 case FTP_USR: /* USER, LOGIN */
9376 return(hmsga(fhs_usr));
9377 case FTP_MGE: /* MGET */
9378 return(hmsga(fhs_mge));
9379 case FTP_MKD: /* MKDIR */
9380 return(hmsga(fhs_mkd));
9381 case FTP_MOD: /* MODTIME */
9382 return(hmsga(fhs_mod));
9383 case FTP_MPU: /* MPUT */
9384 return(hmsga(fhs_mpu));
9385 case FTP_OPN: /* OPEN */
9386 return(hmsga(fhs_opn));
9387 case FTP_OPT: /* OPTS, OPTIONS */
9388 return(hmsga(fhs_opt));
9389 case FTP_PUT: /* PUT, SEND */
9390 return(hmsga(fhs_put));
9391 case FTP_REP: /* REPUT, RESEND */
9392 return(hmsga(fhs_reput));
9393 case FTP_PWD: /* PWD */
9394 return(hmsga(fhs_pwd));
9395 case FTP_QUO: /* QUOTE */
9396 return(hmsga(fhs_quo));
9397 case FTP_RGE: /* REGET */
9398 return(hmsga(fhs_rge));
9399 case FTP_REN: /* RENAME */
9400 return(hmsga(fhs_ren));
9401 case FTP_RES: /* RESET */
9402 return(hmsga(fhs_res));
9403 case FTP_RMD: /* RMDIR */
9404 return(hmsga(fhs_rmd));
9405 case FTP_SIT: /* SITE */
9406 return(hmsga(fhs_sit));
9407 case FTP_SIZ: /* SIZE */
9408 return(hmsga(fhs_siz));
9409 case FTP_STA: /* STATUS */
9410 return(hmsga(fhs_sta));
9411 case FTP_SYS: /* SYSTEM */
9412 return(hmsga(fhs_sys));
9413 case FTP_TYP: /* TYPE */
9414 return(hmsga(fhs_typ));
9415 case FTP_UMA: /* UMASK */
9416 return(hmsga(fhs_uma));
9417 case FTP_CHK: /* CHECK */
9418 return(hmsga(fhs_chk));
9420 return(hmsga(fhs_ena));
9422 return(hmsga(fhs_dis));
9424 printf("Sorry, help available for this command.\n");
9428 return(success = 0);
9434 if ((cx = cmkey(ftpset,nftpset,"","",xxstring)) < 0)
9438 ckstrncpy(tmpbuf,atmbuf,TMPBUFSIZ);
9439 if ((x = cmcfm()) < 0)
9443 printf("Sorry, no help available\n");
9447 printf("\nSyntax: SET FTP parameter value\n");
9448 printf(" Type \"help set ftp ?\" for a list of parameters.\n");
9449 printf(" Type \"help set ftp xxx\" for information about setting\n");
9450 printf(" parameter xxx. Type \"show ftp\" for current values.\n\n");
9454 printf("\nSyntax: SET FTP BUG <name> {ON, OFF}\n");
9456 " Activates a workaround for the named bug in the FTP server.\n");
9457 printf(" Type SET FTP BUG ? for a list of names.\n");
9458 printf(" For each bug, the default is OFF\n\n");
9462 case FTS_ATP: /* "authtype" */
9463 printf("\nSyntax: SET FTP AUTHTYPE list\n");
9464 printf(" Specifies an ordered list of authentication methods to be\n"
9466 printf(" when FTP AUTOAUTHENTICATION is ON. The default list is:\n");
9467 printf(" GSSAPI-KRB5, SRP, KERBEROS_V4, TLS, SSL.\n\n");
9470 case FTS_AUT: /* "autoauthentication" */
9471 printf("\nSyntax:SET FTP AUTOAUTHENTICATION { ON, OFF }\n");
9472 printf(" Tells whether authentication should be negotiated by the\n");
9473 printf(" FTP OPEN command. Default is ON.\n\n");
9476 case FTS_CRY: /* "autoencryption" */
9477 printf("\nSET FTP AUTOENCRYPTION { ON, OFF }\n");
9478 printf(" Tells whether encryption (privacy) should be negotiated\n");
9479 printf(" by the FTP OPEN command. Default is ON.\n\n");
9481 #endif /* FTP_SECURITY */
9483 case FTS_LOG: /* "autologin" */
9484 printf("\nSET FTP AUTOLOGIN { ON, OFF }\n");
9485 printf(" Tells Kermit whether to try to log you in automatically\n");
9486 printf(" as part of the connection process.\n\n");
9490 printf("\nSET FTP DISPLAY { BRIEF, FULLSCREEN, CRT, ... }\n");
9491 printf(" Chooses the file-transfer display style for FTP.\n");
9492 printf(" Like SET TRANSFER DISPLAY but applies only to FTP.\n\n");
9496 case FTS_XLA: /* "character-set-translation" */
9497 printf("\nSET FTP CHARACTER-SET-TRANSLATION { ON, OFF }\n");
9498 printf(" Whether to translate character sets when transferring\n");
9499 printf(" text files with FTP. OFF by default.\n\n");
9502 #endif /* NOCSETS */
9503 case FTS_FNC: /* "collision" */
9506 "Syntax: SET FTP COLLISION { BACKUP,RENAME,UPDATE,DISCARD,APPEND,OVERWRITE }\n"
9508 printf(" Tells what do when an incoming file has the same name as\n");
9509 printf(" an existing file when downloading with FTP.\n\n");
9513 case FTS_CPL: /* "command-protection-level" */
9516 "Syntax: SET FTP COMMAND-PROTECTION-LEVEL { CLEAR,CONFIDENTIAL,PRIVATE,SAFE }"
9520 " Tells what level of protection is applied to the FTP command channel.\n\n");
9522 case FTS_CFW: /* "credential-forwarding" */
9523 printf("\nSyntax: SET FTP CREDENTIAL-FORWARDING { ON, OFF }\n");
9524 printf(" Tells whether end-user credentials are to be forwarded\n");
9525 printf(" to the server if supported by the authentication method\n");
9526 printf(" (GSSAPI-KRB5 only).\n\n");
9528 case FTS_DPL: /* "data-protection-level" */
9531 "Syntax: SET FTP DATA-PROTECTION-LEVEL { CLEAR,CONFIDENTIAL,PRIVATE,SAFE }"
9535 " Tells what level of protection is applied to the FTP data channel.\n\n");
9537 #endif /* FTP_SECURITY */
9539 case FTS_DBG: /* "debug" */
9540 printf("\nSyntax: SET FTP DEBUG { ON, OFF }\n");
9541 printf(" Whether to print FTP protocol messages.\n\n");
9544 case FTS_ERR: /* "error-action" */
9545 printf("\nSyntax: SET FTP ERROR-ACTION { QUIT, PROCEED }\n");
9546 printf(" What to do when an error occurs when transferring a group\n")
9548 printf(" of files: quit and fail, or proceed to the next file.\n\n");
9551 case FTS_CNV: /* "filenames" */
9552 printf("\nSyntax: SET FTP FILENAMES { AUTO, CONVERTED, LITERAL }\n");
9553 printf(" What to do with filenames: convert them, take and use them\n"
9555 printf(" literally; or choose what to do automatically based on the\n"
9557 printf(" OS type of the server. The default is AUTO.\n\n");
9560 case FTS_PSV: /* "passive-mode" */
9561 printf("\nSyntax: SET FTP PASSIVE-MODE { ON, OFF }\n");
9562 printf(" Whether to use passive mode, which helps to get through\n");
9563 printf(" firewalls. ON by default.\n\n");
9566 case FTS_PRM: /* "permissions" */
9567 printf("\nSyntax: SET FTP PERMISSIONS { AUTO, ON, OFF }\n");
9568 printf(" Whether to try to send file permissions when uploading.\n");
9569 printf(" OFF by default. AUTO means only if client and server\n");
9570 printf(" have the same OS type.\n\n");
9573 case FTS_TST: /* "progress-messages" */
9574 printf("\nSyntax: SET FTP PROGRESS-MESSAGES { ON, OFF }\n");
9575 printf(" Whether Kermit should print locally-generated feedback\n");
9576 printf(" messages for each non-file-transfer command.");
9577 printf(" ON by default.\n\n");
9580 case FTS_SPC: /* "send-port-commands" */
9581 printf("\nSyntax: SET FTP SEND-PORT-COMMANDS { ON, OFF }\n");
9582 printf(" Whether Kermit should send a new PORT command for each");
9583 printf(" task.\n\n");
9587 case FTS_CSR: /* "server-character-set" */
9588 printf("\nSyntax: SET FTP SERVER-CHARACTER-SET name\n");
9589 printf(" The name of the character set used for text files on the\n");
9590 printf(" server. Enter a name of '?' for a menu.\n\n");
9592 #endif /* NOCSETS */
9594 case FTS_STO: /* "server-time-offset */
9596 "\nSyntax: SET FTP SERVER-TIME-OFFSET +hh[:mm[:ss]] or -hh[:mm[:ss]]\n");
9598 " Specifies an offset to apply to the server's file timestamps.\n");
9600 " Use this to correct for misconfigured server time or timezone.\n");
9602 " Format: must begin with + or - sign. Hours must be given; minutes\n");
9604 " and seconds are optional: +4 = +4:00 = +4:00:00 (add 4 hours).\n\n");
9607 case FTS_TYP: /* "type" */
9608 printf("\nSyntax: SET FTP TYPE { TEXT, BINARY, TENEX }\n");
9609 printf(" Establishes the default transfer mode.\n");
9610 printf(" TENEX is used for uploading 8-bit binary files to 36-bit\n");
9611 printf(" platforms such as TENEX and TOPS-20 and for downloading\n");
9612 printf(" them again. ASCII is a synonym for TEXT. Normally each\n");
9613 printf(" file's type is determined automatically from its contents\n"
9615 printf(" or its name; SET FTP TYPE does not prevent that, it only\n");
9616 printf(" tells which mode to use when the type can't be determined\n"
9618 printf(" automatically. To completely disable automatic transfer-\n"
9620 printf(" mode switching and force either text or binary mode, give\n"
9622 printf(" the top-level command ASCII or BINARY, as in traditional\n");
9623 printf(" FTP clients.\n\n");
9628 printf("\nSyntax: SET FTP TIMEOUT number-of-seconds\n");
9629 printf(" Establishes a timeout for FTP transfers.\n");
9630 printf(" The timeout applies per network read or write on the data\n");
9631 printf(" connection, not to the whole transfer. By default the\n");
9632 printf(" timeout value is 0, meaning no timeout. Use a positive\n");
9633 printf(" number to escape gracefully from hung data connections or\n");
9634 printf(" directory listings.\n\n");
9636 #endif /* FTP_TIMEOUT */
9640 printf("\nSyntax: SET FTP GET-FILETYPE-SWITCHING { ON, OFF }\n");
9641 printf(" Tells whether GET and MGET should automatically switch\n");
9642 printf(" the appropriate file type, TEXT, BINARY, or TENEX, by\n");
9643 printf(" matching the name of each incoming file with its list of\n");
9644 printf(" FILE TEXT-PATTERNS and FILE BINARY-PATTERNS. ON by\n");
9645 printf(" default. SHOW PATTERNS displays the current pattern\n");
9646 printf(" list. HELP SET FILE to see how to change it.\n");
9648 #endif /* PATTERNS */
9650 case FTS_USN: /* "unique-server-names" */
9651 printf("\nSyntax: SET FTP UNIQUE-SERVER-NAMES { ON, OFF }\n");
9652 printf(" Tells whether to ask the server to create unique names\n");
9653 printf(" for any uploaded file that has the same name as an\n");
9654 printf(" existing file. Default is OFF.\n\n");
9657 case FTS_VBM: /* "verbose-mode" */
9658 printf("\nSyntax: SET FTP VERBOSE-MODE { ON, OFF }\n");
9659 printf(" Whether to display all responses from the FTP server.\n");
9660 printf(" OFF by default.\n\n");
9664 printf("\nSyntax: SET FTP DATES { ON, OFF }\n");
9665 printf(" Whether to set date of incoming files from the file date\n");
9666 printf(" on the server. ON by default. Note: there is no way to\n")
9668 printf(" set the date on files uploaded to the server. Also note\n");
9669 printf(" that not all servers support this feature.\n\n");
9673 printf("\nSyntax: SET FTP ANONYMOUS-PASSWORD [ text ]\n");
9674 printf(" Password to supply automatically on anonymous FTP\n");
9675 printf(" connections instead of the default user@host.\n");
9676 printf(" Omit optional text to restore default.\n\n");
9680 printf("Sorry, help not available for \"set ftp %s\"\n",tmpbuf);
9694 char srp_user[BUFSIZ]; /* where is BUFSIZ defined? */
9697 #endif /* FTP_SRP */
9699 static int kerror; /* Needed for all auth types */
9701 static struct sockaddr_in hisctladdr;
9702 static struct sockaddr_in hisdataaddr;
9703 static struct sockaddr_in data_addr;
9704 static int data = -1;
9705 static int ptflag = 0;
9706 static struct sockaddr_in myctladdr;
9712 #endif /* COMMENT */
9715 static int cpend = 0; /* No pending replies */
9718 extern SSL *ssl_ftp_con;
9719 extern SSL_CTX *ssl_ftp_ctx;
9720 extern SSL *ssl_ftp_data_con;
9721 extern int ssl_ftp_active_flag;
9722 extern int ssl_ftp_data_active_flag;
9725 /* f t p c m d -- Send a command to the FTP server */
9728 char * cmd: The command to send.
9729 char * arg: The argument (e.g. a filename).
9730 int lcs: The local character set index.
9731 int rcs: The remote (server) character set index.
9732 int vbm: Verbose mode:
9733 0 = force verbosity off
9734 >0 = force verbosity on
9736 If arg is given (not NULL or empty) and lcs != rcs and both are > -1,
9737 and neither lcs or rcs is UCS-2, the arg is translated from the local
9738 character set to the remote one before sending the result to the server.
9741 0 on failure with ftpcode = -1
9742 >= 0 on success (getreply() result) with ftpcode = 0.
9744 static char xcmdbuf[RFNBUFSIZ];
9747 ftpcmd(cmd,arg,lcs,rcs,vbm) char * cmd, * arg; int lcs, rcs, vbm; {
9749 int r = 0, x = 0, fc = 0, len = 0, cmdlen = 0, q = -1;
9752 if (ftp_deb) /* DEBUG */
9754 else if (quiet || dpyactive) /* QUIET or File Transfer Active */
9756 else if (vbm < 0) /* VERBOSE */
9762 cmdlen = (int)strlen(cmd);
9763 len = cmdlen + (int)strlen(arg) + 1;
9765 if (ftp_deb /* && !dpyactive */ ) {
9767 if (ftp_prx) printf("%s ", ftp_host);
9768 #endif /* FTP_PROXY */
9770 if (!anonymous && strcmp("PASS",cmd) == 0)
9771 printf("PASS XXXX");
9773 printf("%s %s",cmd,arg);
9776 /* bzero(xcmdbuf,RFNBUFSIZ); */
9777 ckmakmsg(xcmdbuf,RFNBUFSIZ, cmd, *arg ? " " : "", arg, NULL);
9781 debug(F110,"ftpcmd cmd",cmd,0);
9782 debug(F110,"ftpcmd arg",arg,0);
9783 debug(F101,"ftpcmd lcs","",lcs);
9784 debug(F101,"ftpcmd rcs","",rcs);
9788 if (csocket == -1) {
9789 perror("No control connection for command");
9794 oldintr = signal(SIGINT, cmdcancel);
9797 if (*arg && /* If an arg was given */
9798 lcs > -1 && /* and a local charset */
9799 rcs > -1 && /* and a remote charset */
9800 lcs != rcs && /* and the two are not the same */
9801 lcs != FC_UCS2 && /* and neither one is UCS-2 */
9802 rcs != FC_UCS2 /* ... */
9804 initxlate(lcs,rcs); /* Translate arg from lcs to rcs */
9805 xgnbp = arg; /* Global pointer to input string */
9806 rfnptr = rfnbuf; /* Global pointer to output buffer */
9809 if ((c0 = xgnbyte(FC_UCS2,lcs,strgetc)) < 0) break;
9810 if (xpnbyte(c0,TC_UCS2,rcs,strputc) < 0) break;
9813 We have to copy here instead of translating directly into
9814 xcmdbuf[] so strputc() can check length. Alternatively we could
9815 write yet another xpnbyte() output function.
9817 if ((int)strlen(rfnbuf) > (RFNBUFSIZ - (cmdlen+1))) {
9818 printf("?FTP command too long: %s + arg\n",cmd);
9822 x = ckstrncpy(&xcmdbuf[cmdlen+1], rfnbuf, RFNBUFSIZ - (cmdlen+1));
9824 #endif /* NOCSETS */
9826 s = xcmdbuf; /* Command to send to server */
9829 if (deblog) { /* Log it */
9830 if (!anonymous && !ckstrcmp(s,"PASS ",5,0)) {
9831 /* But don't log passwords */
9832 debug(F110,"FTP SENT ","PASS XXXX",0);
9834 debug(F110,"FTP SENT ",s,0);
9839 #ifdef CK_ENCRYPTION
9841 #endif /* CK_ENCRYPTION */
9842 if (scommand(s) == 0) { /* Send it. */
9843 signal(SIGINT, oldintr);
9847 x = !strcmp(cmd,"QUIT"); /* Is it the QUIT command? */
9848 if (x) /* In case we're interrupted */
9849 connected = 0; /* while waiting for the reply... */
9851 fc = 0; /* Function code for getreply() */
9852 if (!strncmp(cmd,"AUTH ",5) /* Must parse AUTH reply */
9854 && strncmp(cmd, "HOST ",5)
9855 #endif /* FTPHOST */
9858 } else if (!ckstrcmp(cmd,"FEAT",-1,0)) { /* Must parse FEAT reply */
9859 fc = GRF_FEAT; /* But FEAT not widely understood */
9860 if (!ftp_deb) /* So suppress error messages */
9863 r = getreply(x, /* Expect connection to close */
9864 lcs,rcs, /* Charsets */
9865 vbm, /* Verbosity */
9866 fc /* Function code */
9871 #ifdef CK_ENCRYPTION
9872 if (ftpcode == 533 && ftp_cpl == FPL_PRV) {
9874 "ENC command not supported at server; retrying under MIC...\n");
9878 #endif /* CK_ENCRYPTION */
9880 if (cancelfile && oldintr != SIG_IGN)
9882 #endif /* COMMENT */
9883 signal(SIGINT, oldintr);
9889 debug(F100,"lostpeer","",0);
9891 if (csocket != -1) {
9893 if (ssl_ftp_active_flag) {
9894 SSL_shutdown(ssl_ftp_con);
9895 SSL_free(ssl_ftp_con);
9897 ssl_ftp_active_flag = 0;
9902 socket_close(csocket);
9903 #else /* TCPIPLIB */
9905 shutdown(csocket, 1+1);
9906 #endif /* USE_SHUTDOWN */
9908 #endif /* TCPIPLIB */
9913 if (ssl_ftp_data_active_flag) {
9914 SSL_shutdown(ssl_ftp_data_con);
9915 SSL_free(ssl_ftp_data_con);
9916 ssl_ftp_data_active_flag = 0;
9917 ssl_ftp_data_con = NULL;
9922 #else /* TCPIPLIB */
9924 shutdown(data, 1+1);
9925 #endif /* USE_SHUTDOWN */
9927 #endif /* TCPIPLIB */
9935 ftp_cpl = ftp_dpl = FPL_CLR;
9938 #endif /* CKLOGDIAL */
9941 if (autolocus) /* Auotomatic locus switching... */
9942 setlocus(1,1); /* Switch locus to local. */
9945 DialerSend(OPT_KERMIT_HANGUP, 0);
9951 if (csocket != -1) {
9953 socket_close(csocket);
9954 #else /* TCPIPLIB */
9956 shutdown(csocket, 1+1);
9957 #endif /* USE_SHUTDOWN */
9959 #endif /* TCPIPLIB */
9966 ftp_cpl = ftp_dpl = FPL_CLR;
9970 #endif /* FTP_PROXY */
9980 extern int quitting;
9983 ftp_xfermode = xfermode;
9984 if (!ftp_vbm && !quiet)
9986 ftpcmd("QUIT",NULL,0,0,ftp_vbm);
9989 if (ssl_ftp_active_flag) {
9990 SSL_shutdown(ssl_ftp_con);
9991 SSL_free(ssl_ftp_con);
9993 ssl_ftp_active_flag = 0;
9998 socket_close(csocket);
9999 #else /* TCPIPLIB */
10000 #ifdef USE_SHUTDOWN
10001 shutdown(csocket, 1+1);
10002 #endif /* USE_SHUTDOWN */
10004 #endif /* TCPIPLIB */
10020 #endif /* FTP_PROXY */
10025 #endif /* CKLOGDIAL */
10027 /* Unprefixed file management commands are executed locally */
10028 if (autolocus && !ftp_cmdlin && !quitting) {
10033 DialerSend(OPT_KERMIT_HANGUP, 0);
10039 ftpopen(remote, service, use_tls) char * remote, * service; int use_tls; {
10043 printf("?Already connected to %s, use FTP CLOSE first.\n", ftp_host);
10049 #endif /* FTPHOST */
10051 ftp_srvtyp[0] = NUL;
10052 if (!service) service = "";
10053 if (!*service) service = use_tls ? "ftps" : "ftp";
10055 if (!isdigit(service[0])) {
10056 struct servent *destsp;
10057 destsp = getservbyname(service, "tcp");
10059 if (!ckstrcmp(service,"ftp",-1,0)) {
10061 } else if (!ckstrcmp(service,"ftps",-1,0)) {
10064 printf("?Bad port name - \"%s\"\n", service);
10069 ftp_port = destsp->s_port;
10070 ftp_port = ntohs((unsigned short)ftp_port); /* SMS 2007/02/15 */
10073 ftp_port = atoi(service);
10074 if (ftp_port <= 0) {
10075 printf("?Bad port name - \"%s\"\n", service);
10079 host = ftp_hookup(remote, ftp_port, use_tls);
10081 ckstrncpy(ftp_user_host,remote,MAX_DNS_NAMELEN);
10082 connected = 1; /* Set FTP defaults */
10083 ftp_cpl = ftp_dpl = FPL_CLR;
10084 curtype = FTT_ASC; /* Server uses ASCII mode */
10088 strcpy(bytename, "8");
10091 #ifdef FTP_SECURITY
10096 && ck_crypt_is_installed()
10100 printf("FTP Command channel is Private (encrypted)\n");
10102 if (setpbsz(DEFAULT_PBSZ) < 0) {
10103 /* a failure here is most likely caused by a mixup */
10104 /* in the session key used by client and server */
10105 printf("?Protection buffer size negotiation failed\n");
10108 if (ftpcmd("PROT P",NULL,0,0,ftp_vbm) == REPLY_COMPLETE) {
10110 printf("FTP Data channel is Private (encrypted)\n");
10113 printf("?Unable to enable encryption on data channel\n");
10121 #endif /* FTP_SECURITY */
10122 if (ftp_log) /* ^^^ */
10128 ftp_xfermode = xfermode;
10132 #endif /* CKLOGDIAL */
10134 DialerSend(OPT_KERMIT_CONNECT, 0);
10136 passivemode = ftp_psv;
10137 sendport = ftp_spc;
10143 if (ucbuf == NULL) {
10144 actualbuf = DEFAULT_PBSZ;
10145 while (actualbuf && (ucbuf = (CHAR *)malloc(actualbuf)) == NULL)
10149 ucbufsiz = actualbuf - FUDGE_FACTOR;
10150 debug(F101,"ftpopen ucbufsiz","",ucbufsiz);
10154 printf("?Can't FTP connect to %s:%s\n",remote,service);
10165 if (ssl_debug_flag) {
10166 fprintf(stderr,"SSL DEBUG ACTIVE\n");
10168 /* for the moment I want the output on screen */
10170 if (ssl_ftp_data_con != NULL) {
10171 SSL_free(ssl_ftp_data_con);
10172 ssl_ftp_data_con = NULL;
10174 if (ssl_ftp_con != NULL) {
10175 SSL_free(ssl_ftp_con);
10178 if (ssl_ftp_ctx != NULL) {
10179 SSL_CTX_free(ssl_ftp_ctx);
10180 ssl_ftp_ctx = NULL;
10183 /* The SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
10184 * was added to OpenSSL 0.9.6e and 0.9.7. It does not exist in previous
10187 #ifndef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
10188 #define SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS 0L
10190 if (auth_type && !strcmp(auth_type,"TLS")) {
10191 ssl_ftp_ctx=SSL_CTX_new(SSLv3_client_method());
10194 SSL_CTX_set_options(ssl_ftp_ctx,
10195 SSL_OP_SINGLE_DH_USE|SSL_OP_EPHEMERAL_RSA
10198 ssl_ftp_ctx = SSL_CTX_new(ftp_bug_use_ssl_v2 ? SSLv23_client_method() :
10199 SSLv3_client_method());
10202 SSL_CTX_set_options(ssl_ftp_ctx,
10203 (ftp_bug_use_ssl_v2 ? 0 : SSL_OP_NO_SSLv2)|
10204 SSL_OP_SINGLE_DH_USE|SSL_OP_EPHEMERAL_RSA
10207 SSL_CTX_set_default_passwd_cb(ssl_ftp_ctx,
10208 (pem_password_cb *)ssl_passwd_callback);
10209 SSL_CTX_set_info_callback(ssl_ftp_ctx,ssl_client_info_callback);
10210 SSL_CTX_set_session_cache_mode(ssl_ftp_ctx,SSL_SESS_CACHE_CLIENT);
10214 /* The defaults in the SSL crypto library are not appropriate for OS/2 */
10216 char path[CKMAXPATH];
10217 extern char exedir[];
10219 ckmakmsg(path,CKMAXPATH,exedir,"certs",NULL,NULL);
10220 if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,NULL,path) == 0) {
10221 debug(F110,"ftp ssl_auth unable to load path",path,0);
10222 if (ssl_debug_flag)
10223 printf("?Unable to load verify-dir: %s\r\n",path);
10226 ckmakmsg(path,CKMAXPATH,
10227 (char *)GetAppData(1),"kermit 95/certs",NULL,NULL);
10228 if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,NULL,path) == 0) {
10229 debug(F110,"ftp ssl_auth unable to load path",path,0);
10230 if (ssl_debug_flag)
10231 printf("?Unable to load verify-dir: %s\r\n",path);
10234 ckmakmsg(path,CKMAXPATH,
10235 (char *)GetAppData(0),"kermit 95/certs",NULL,NULL);
10236 if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,NULL,path) == 0) {
10237 debug(F110,"ftp ssl_auth unable to load path",path,0);
10238 if (ssl_debug_flag)
10239 printf("?Unable to load verify-dir: %s\r\n",path);
10242 ckmakmsg(path,CKMAXPATH,exedir,"ca_certs.pem",NULL,NULL);
10243 if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,path,NULL) == 0) {
10244 debug(F110,"ftp ssl_auth unable to load path",path,0);
10245 if (ssl_debug_flag)
10246 printf("?Unable to load verify-file: %s\r\n",path);
10249 ckmakmsg(path,CKMAXPATH,(char *)GetAppData(1),
10250 "kermit 95/ca_certs.pem",NULL,NULL);
10251 if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,path,NULL) == 0) {
10252 debug(F110,"ftp ssl_auth unable to load path",path,0);
10253 if (ssl_debug_flag)
10254 printf("?Unable to load verify-file: %s\r\n",path);
10257 ckmakmsg(path,CKMAXPATH,(char *)GetAppData(0),
10258 "kermit 95/ca_certs.pem",NULL,NULL);
10259 if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,path,NULL) == 0) {
10260 debug(F110,"ftp ssl_auth unable to load path",path,0);
10261 if (ssl_debug_flag)
10262 printf("?Unable to load verify-file: %s\r\n",path);
10266 /* The defaults in the SSL crypto library are not appropriate for OS/2 */
10269 char path[CKMAXPATH];
10270 extern char exedir[];
10272 ckmakmsg(path,CKMAXPATH,exedir,"certs",NULL,NULL);
10273 if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,NULL,path) == 0) {
10274 debug(F110,"ftp ssl_auth unable to load path",path,0);
10275 if (ssl_debug_flag)
10276 printf("?Unable to load verify-dir: %s\r\n",path);
10278 ckmakmsg(path,CKMAXPATH,exedir,"ca_certs.pem",NULL,NULL);
10279 if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,path,NULL) == 0) {
10280 debug(F110,"ftp ssl_auth unable to load path",path,0);
10281 if (ssl_debug_flag)
10282 printf("?Unable to load verify-file: %s\r\n",path);
10287 SSL_CTX_set_default_verify_paths(ssl_ftp_ctx);
10290 if (ssl_verify_file &&
10291 SSL_CTX_load_verify_locations(ssl_ftp_ctx,ssl_verify_file,NULL) == 0) {
10293 "ftp ssl auth unable to load ssl_verify_file",
10297 if (ssl_debug_flag)
10298 printf("?Unable to load verify-file: %s\r\n",ssl_verify_file);
10300 if (ssl_verify_dir &&
10301 SSL_CTX_load_verify_locations(ssl_ftp_ctx,NULL,ssl_verify_dir) == 0) {
10303 "ftp ssl auth unable to load ssl_verify_dir",
10307 if (ssl_debug_flag)
10308 printf("?Unable to load verify-dir: %s\r\n",ssl_verify_dir);
10311 /* set up the new CRL Store */
10312 crl_store = (X509_STORE *)X509_STORE_new();
10315 char path[CKMAXPATH];
10316 extern char exedir[];
10318 ckmakmsg(path,CKMAXPATH,exedir,"crls",NULL,NULL);
10319 if (X509_STORE_load_locations(crl_store,NULL,path) == 0) {
10320 debug(F110,"ftp ssl auth unable to load dir",path,0);
10321 if (ssl_debug_flag)
10322 printf("?Unable to load crl-dir: %s\r\n",path);
10325 ckmakmsg(path,CKMAXPATH,
10326 (char *)GetAppData(1),"kermit 95/crls",NULL,NULL);
10327 if (X509_STORE_load_locations(crl_store,NULL,path) == 0) {
10328 debug(F110,"ftp ssl auth unable to load dir",path,0);
10329 if (ssl_debug_flag)
10330 printf("?Unable to load crl-dir: %s\r\n",path);
10332 ckmakmsg(path,CKMAXPATH,
10333 (char *)GetAppData(0),"kermit 95/crls",NULL,NULL);
10334 if (X509_STORE_load_locations(crl_store,NULL,path) == 0) {
10335 debug(F110,"ftp ssl auth unable to load dir",path,0);
10336 if (ssl_debug_flag)
10337 printf("?Unable to load crl-dir: %s\r\n",path);
10341 ckmakmsg(path,CKMAXPATH,exedir,"ca_crls.pem",NULL,NULL);
10342 if (X509_STORE_load_locations(crl_store,path,NULL) == 0) {
10343 debug(F110,"ftp ssl auth unable to load file",path,0);
10344 if (ssl_debug_flag)
10345 printf("?Unable to load crl-file: %s\r\n",path);
10348 ckmakmsg(path,CKMAXPATH,(char *)GetAppData(1),
10349 "kermit 95/ca_crls.pem",NULL,NULL);
10350 if (X509_STORE_load_locations(crl_store,path,NULL) == 0) {
10351 debug(F110,"ftp ssl auth unable to load file",path,0);
10352 if (ssl_debug_flag)
10353 printf("?Unable to load crl-file: %s\r\n",path);
10355 ckmakmsg(path,CKMAXPATH,(char *)GetAppData(0),
10356 "kermit 95/ca_crls.pem",NULL,NULL);
10357 if (X509_STORE_load_locations(crl_store,path,NULL) == 0) {
10358 debug(F110,"ftp ssl auth unable to load file",path,0);
10359 if (ssl_debug_flag)
10360 printf("?Unable to load crl-file: %s\r\n",path);
10365 if (ssl_crl_file || ssl_crl_dir) {
10366 if (ssl_crl_file &&
10367 X509_STORE_load_locations(crl_store,ssl_crl_file,NULL) == 0) {
10369 "ftp ssl auth unable to load ssl_crl_file",
10373 if (ssl_debug_flag)
10374 printf("?Unable to load crl-file: %s\r\n",ssl_crl_file);
10377 X509_STORE_load_locations(crl_store,NULL,ssl_crl_dir) == 0) {
10379 "ftp ssl auth unable to load ssl_crl_dir",
10383 if (ssl_debug_flag)
10384 printf("?Unable to load crl-dir: %s\r\n",ssl_crl_dir);
10387 X509_STORE_set_default_paths(crl_store);
10390 SSL_CTX_set_verify(ssl_ftp_ctx,ssl_verify_flag,
10391 ssl_client_verify_callback);
10392 ssl_verify_depth = -1;
10393 ssl_ftp_con=(SSL *)SSL_new(ssl_ftp_ctx);
10394 tls_load_certs(ssl_ftp_ctx,ssl_ftp_con,0);
10395 SSL_set_fd(ssl_ftp_con,csocket);
10396 SSL_set_verify(ssl_ftp_con,ssl_verify_flag,NULL);
10397 if (ssl_cipher_list) {
10398 SSL_set_cipher_list(ssl_ftp_con,ssl_cipher_list);
10401 if (p = getenv("SSL_CIPHER")) {
10402 SSL_set_cipher_list(ssl_ftp_con,p);
10404 SSL_set_cipher_list(ssl_ftp_con,DEFAULT_CIPHER_LIST);
10407 if (ssl_debug_flag) {
10408 fprintf(stderr,"=>START SSL/TLS connect on COMMAND\n");
10411 if (SSL_connect(ssl_ftp_con) <= 0) {
10412 static char errbuf[1024];
10413 ckmakmsg(errbuf,1024,"ftp: SSL/TLS connect COMMAND error: ",
10414 ERR_error_string(ERR_get_error(),NULL),NULL,NULL);
10415 fprintf(stderr,"%s\n", errbuf);
10417 ssl_ftp_active_flag=0;
10418 SSL_free(ssl_ftp_con);
10419 ssl_ftp_con = NULL;
10421 ssl_ftp_active_flag = 1;
10423 if (!ssl_certsok_flag && !tls_is_krb5(1)) {
10424 char *subject = ssl_get_subject_name(ssl_ftp_con);
10427 if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
10428 debug(F110,"ssl_auth","[SSL - FAILED]",0);
10429 return(ssl_ftp_active_flag = 0);
10431 if (uq_ok("Warning: Server didn't provide a certificate\n",
10432 "Continue? (Y/N)",3,NULL,0) <= 0) {
10433 debug(F110, "ssl_auth","[SSL - FAILED]",0);
10434 return(ssl_ftp_active_flag = 0);
10437 } else if (ssl_check_server_name(ssl_ftp_con, ftp_user_host)) {
10438 debug(F110,"ssl_auth","[SSL - FAILED]",0);
10439 return(ssl_ftp_active_flag = 0);
10442 debug(F110,"ssl_auth","[SSL - OK]",0);
10443 ssl_display_connect_details(ssl_ftp_con,0,ssl_verbose_flag);
10445 if (ssl_debug_flag) {
10446 fprintf(stderr,"=>DONE SSL/TLS connect on COMMAND\n");
10449 return(ssl_ftp_active_flag);
10451 #endif /* CK_SSL */
10454 cmdcancel(sig) int sig; {
10456 /* In Unix we "chain" to trap(), which prints this */
10459 debug(F100,"ftp cmdcancel caught SIGINT ","",0);
10461 secure_getc(0,1); /* Initialize net input buffers */
10467 if (ptflag) /* proxy... */
10468 longjmp(ptcancel,1);
10469 #endif /* FTP_PROXY */
10470 debug(F100,"ftp cmdcancel chain to trap()...","",0);
10473 debug(F100,"ftp cmdcancel return from trap()...","",0);
10475 debug(F100,"ftp cmdcancel PostCtrlCSem()...","",0);
10482 scommand(char * s) /* Was secure_command() */
10484 scommand(s) char * s;
10485 #endif /* CK_ANSIC */
10487 int length = 0, len2;
10488 char in[FTP_BUFSIZ], out[FTP_BUFSIZ];
10490 if (ssl_ftp_active_flag) {
10492 length = strlen(s) + 2;
10493 length = ckmakmsg(out,FTP_BUFSIZ,s,"\r\n",NULL,NULL);
10494 rc = SSL_write(ssl_ftp_con,out,length);
10495 error = SSL_get_error(ssl_ftp_con,rc);
10497 case SSL_ERROR_NONE:
10499 case SSL_ERROR_WANT_WRITE:
10500 case SSL_ERROR_WANT_READ:
10501 case SSL_ERROR_SYSCALL:
10504 int gle = GetLastError();
10507 case SSL_ERROR_WANT_X509_LOOKUP:
10508 case SSL_ERROR_SSL:
10509 case SSL_ERROR_ZERO_RETURN:
10515 #endif /* CK_SSL */
10517 if (auth_type && ftp_cpl != FPL_CLR) {
10519 if (ck_srp_is_installed() && (strcmp(auth_type,"SRP") == 0))
10520 if ((length = srp_encode(ftp_cpl == FPL_PRV,
10524 fprintf(stderr, "SRP failed to encode message\n");
10527 #endif /* FTP_SRP */
10529 if (ck_krb4_is_installed() &&
10530 (strcmp(auth_type, "KERBEROS_V4") == 0)) {
10531 if (ftp_cpl == FPL_PRV) {
10533 krb_mk_priv((CHAR *)s, (CHAR *)out,
10534 strlen(s), ftp_sched,
10539 #endif /* KRB524 */
10540 &myctladdr, &hisctladdr);
10543 krb_mk_safe((CHAR *)s,
10550 #endif /* KRB524 */
10551 &myctladdr, &hisctladdr);
10553 if (length == -1) {
10554 fprintf(stderr, "krb_mk_%s failed for KERBEROS_V4\n",
10555 ftp_cpl == FPL_PRV ? "priv" : "safe");
10559 #endif /* FTP_KRB4 */
10561 /* Scommand (based on level) */
10562 if (ck_gssapi_is_installed() && (strcmp(auth_type, "GSSAPI") == 0)) {
10563 gss_buffer_desc in_buf, out_buf;
10564 OM_uint32 maj_stat, min_stat;
10567 in_buf.length = strlen(s) + 1;
10568 maj_stat = gss_seal(&min_stat, gcontext,
10569 (ftp_cpl==FPL_PRV), /* private */
10571 &in_buf, &conf_state,
10573 if (maj_stat != GSS_S_COMPLETE) { /* Generally need to deal */
10574 user_gss_error(maj_stat, min_stat,
10575 (ftp_cpl==FPL_PRV)?
10576 "gss_seal ENC didn't complete":
10577 "gss_seal MIC didn't complete");
10578 } else if ((ftp_cpl == FPL_PRV) && !conf_state) {
10579 fprintf(stderr, "GSSAPI didn't encrypt message");
10582 fprintf(stderr, "sealed (%s) %d bytes\n",
10583 ftp_cpl==FPL_PRV?"ENC":"MIC",
10585 memcpy(out, out_buf.value,
10586 length=out_buf.length);
10587 gss_release_buffer(&min_stat, &out_buf);
10590 #endif /* FTP_GSSAPI */
10591 /* Other auth types go here ... */
10594 if ((kerror = radix_encode((CHAR *)out, (CHAR *)in,
10595 length, &len2, RADIX_ENCODE))
10597 fprintf(stderr,"Couldn't base 64 encode command (%s)\n",
10598 radix_error(kerror));
10602 fprintf(stderr, "scommand(%s)\nencoding %d bytes\n", s, length);
10603 len2 = ckmakmsg(out,
10605 ftp_cpl == FPL_PRV ? "ENC " : "MIC ",
10610 send(csocket,(SENDARG2TYPE)out,len2,0);
10612 char out[FTP_BUFSIZ];
10613 int len = ckmakmsg(out,FTP_BUFSIZ,s,"\r\n",NULL,NULL);
10614 send(csocket,(SENDARG2TYPE)out,len,0);
10621 static char inbuf[4096];
10622 static int bp = 0, ep = 0;
10628 if (ssl_ftp_active_flag) {
10630 rc = SSL_read(ssl_ftp_con,inbuf,4096);
10631 error = SSL_get_error(ssl_ftp_con,rc);
10633 case SSL_ERROR_NONE:
10635 case SSL_ERROR_WANT_WRITE:
10636 case SSL_ERROR_WANT_READ:
10638 case SSL_ERROR_SYSCALL:
10639 if (rc == 0) { /* EOF */
10643 int gle = GetLastError();
10647 case SSL_ERROR_WANT_X509_LOOKUP:
10648 case SSL_ERROR_SSL:
10649 case SSL_ERROR_ZERO_RETURN:
10654 #endif /* CK_SSL */
10655 rc = recv(csocket,(char *)inbuf,4096,0);
10660 return(inbuf[bp++]);
10663 /* x l a t e c -- Translate a character */
10666 fc = Function code: 0 = translate, 1 = initialize.
10667 c = Character (as int).
10668 incs = Index of charset to translate from.
10669 outcs = Index of charset to translate to.
10676 xlatec(fc,c,incs,outcs) int fc, c, incs, outcs; {
10680 static char buf[128];
10684 if (fc == 1) { /* Initialize */
10685 cx = 0; /* Catch-up buffer write index */
10686 xgnbp = buf; /* Catch-up buffer read pointer */
10687 buf[0] = NUL; /* Buffer is empty */
10690 if (cx >= 127) { /* Catch-up buffer full */
10691 debug(F100,"xlatec overflow","",0); /* (shouldn't happen) */
10692 printf("?Translation buffer overflow\n");
10695 /* Add char to buffer. */
10696 /* The buffer won't grow unless incs is a multibyte set, e.g. UTF-8. */
10698 debug(F000,"xlatec buf",ckitoa(cx),c);
10702 while ((c0 = xgnbyte(FC_UCS2,incs,strgetc)) > -1) {
10703 if (xpnbyte(c0,TC_UCS2,outcs,NULL) < 0) /* (NULL was xprintc) */
10706 /* If we're caught up, reinitialize the buffer */
10707 return((cx == (xgnbp - buf)) ? xlatec(1,0,0,0) : 0);
10708 #endif /* NOCSETS */
10712 /* p a r s e f e a t */
10714 /* Note: for convenience we align keyword values with table indices */
10715 /* If you need to insert a new keyword, adjust the SFT_xxx definitions */
10717 static struct keytab feattab[] = {
10718 { "$$$$", 0, 0 }, /* Dummy for sfttab[0] */
10719 { "AUTH", SFT_AUTH, 0 },
10720 { "LANG", SFT_LANG, 0 },
10721 { "MDTM", SFT_MDTM, 0 },
10722 { "MLST", SFT_MLST, 0 },
10723 { "PBSZ", SFT_PBSZ, 0 },
10724 { "PROT", SFT_PROT, 0 },
10725 { "REST", SFT_REST, 0 },
10726 { "SIZE", SFT_SIZE, 0 },
10727 { "TVFS", SFT_TVFS, 0 },
10728 { "UTF8", SFT_UTF8, 0 }
10730 static int nfeattab = (sizeof(feattab) / sizeof(struct keytab));
10732 #define FACT_CSET 1
10733 #define FACT_CREA 2
10734 #define FACT_LANG 3
10735 #define FACT_MTYP 4
10736 #define FACT_MDTM 5
10737 #define FACT_PERM 6
10738 #define FACT_SIZE 7
10739 #define FACT_TYPE 8
10740 #define FACT_UNIQ 9
10742 static struct keytab facttab[] = {
10743 { "CHARSET", FACT_CSET, 0 },
10744 { "CREATE", FACT_CREA, 0 },
10745 { "LANG", FACT_LANG, 0 },
10746 { "MEDIA-TYPE", FACT_MTYP, 0 },
10747 { "MODIFY", FACT_MDTM, 0 },
10748 { "PERM", FACT_PERM, 0 },
10749 { "SIZE", FACT_SIZE, 0 },
10750 { "TYPE", FACT_TYPE, 0 },
10751 { "UNIQUE", FACT_UNIQ, 0 }
10753 static int nfacttab = (sizeof(facttab) / sizeof(struct keytab));
10755 static struct keytab ftyptab[] = {
10756 { "CDIR", FTYP_CDIR, 0 },
10757 { "DIR", FTYP_DIR, 0 },
10758 { "FILE", FTYP_FILE, 0 },
10759 { "PDIR", FTYP_PDIR, 0 }
10761 static int nftyptab = (sizeof(ftyptab) / sizeof(struct keytab));
10764 parsefeat(s) char * s; { /* Parse a FEATURE response */
10771 for (i = 0; i < 4; i++) {
10776 if (s[i] && s[i] != SP && s[i] != CR && s[i] != LF)
10779 /* xlookup requires a full (but case independent) match */
10780 i = xlookup(feattab,kwbuf,nfeattab,&x);
10781 debug(F111,"ftp parsefeat",s,i);
10782 if (i < 0 || i > 15)
10786 case SFT_MDTM: /* Controlled by ENABLE/DISABLE */
10787 sfttab[i] = mdtmok;
10788 if (mdtmok) sfttab[0]++;
10790 case SFT_MLST: /* ditto */
10791 sfttab[i] = mlstok;
10792 if (mlstok) sfttab[0]++;
10794 case SFT_SIZE: /* ditto */
10795 sfttab[i] = sizeok;
10796 if (sizeok) sfttab[0]++;
10798 case SFT_AUTH: /* ditto */
10799 sfttab[i] = ftp_aut;
10800 if (ftp_aut) sfttab[0]++;
10802 default: /* Others */
10809 parsefacts(s) char * s; { /* Parse MLS[DT] File Facts */
10812 if (!s) return(NULL);
10813 if (!*s) return(NULL);
10815 /* Maybe we should make a copy of s so we can poke it... */
10817 while ((p = ckstrchr(s,'='))) {
10818 *p = NUL; /* s points to fact */
10819 i = xlookup(facttab,s,nfacttab,&x);
10820 debug(F111,"ftp parsefact fact",s,i);
10822 s = p+1; /* Now s points to arg */
10823 p = ckstrchr(s,';');
10825 p = ckstrchr(s,SP);
10827 debug(F110,"ftp parsefact end-of-val search fail",s,0);
10831 debug(F110,"ftp parsefact valu",s,0);
10833 case FACT_CSET: /* Ignore these for now */
10840 case FACT_MDTM: /* Modtime */
10841 makestr(&havemdtm,s);
10842 debug(F110,"ftp parsefact mdtm",havemdtm,0);
10844 case FACT_SIZE: /* Size */
10845 havesize = ckatofs(s);
10846 debug(F101,"ftp parsefact size","",havesize);
10848 case FACT_TYPE: /* Type */
10849 j = xlookup(ftyptab,s,nftyptab,NULL);
10850 debug(F111,"ftp parsefact type",s,j);
10851 havetype = (j < 1) ? 0 : j;
10855 s = p+1; /* s points next fact or name */
10857 while (*s == SP) /* Skip past spaces. */
10859 if (!*s) /* Make sure we still have a name */
10861 debug(F110,"ftp parsefact name",s,0);
10865 /* g e t r e p l y -- (to an FTP command sent to server) */
10867 /* vbm = 1 (verbose); 0 (quiet except for error messages); 9 (super quiet) */
10870 getreply(expecteof,lcs,rcs,vbm,fc) int expecteof, lcs, rcs, vbm, fc; {
10871 /* lcs, rcs, vbm parameters as in ftpcmd() */
10872 register int i, c, n;
10878 int originalcode = 0, continuation = 0;
10882 char ibuf[FTP_BUFSIZ], obuf[FTP_BUFSIZ]; /* (these are pretty big...) */
10886 auth = (fc == GRF_AUTH);
10889 debug(F101,"ftp getreply lcs","",lcs);
10890 debug(F101,"ftp getreply rcs","",rcs);
10891 if (lcs > -1 && rcs > -1 && lcs != rcs) {
10893 initxlate(rcs,lcs);
10894 xlatec(1,0,rcs,lcs);
10896 #endif /* NOCSETS */
10897 debug(F101,"ftp getreply fc","",fc);
10905 if (ftp_deb) /* DEBUG */
10907 else if (quiet || dpyactive) /* QUIET or File Transfer Active */
10909 else if (vbm < 0) /* VERBOSE */
10914 reply_ptr = reply_buf;
10916 oldintr = signal(SIGINT, cmdcancel);
10917 for (count = 0;; count++) {
10919 dig = n = ftpcode = i = 0;
10920 cp = ftp_reply_str;
10921 while ((c = ibuf[0] ? ibuf[i++] : mygetc()) != '\n') {
10922 if (c == IAC) { /* Handle telnet commands */
10923 switch (c = mygetc()) {
10932 if (ssl_ftp_active_flag) {
10934 rc = SSL_write(ssl_ftp_con,obuf,3);
10935 error = SSL_get_error(ssl_ftp_con,rc);
10937 case SSL_ERROR_NONE:
10939 case SSL_ERROR_WANT_WRITE:
10940 case SSL_ERROR_WANT_READ:
10942 case SSL_ERROR_SYSCALL:
10943 if (rc == 0) { /* EOF */
10947 int gle = GetLastError();
10951 case SSL_ERROR_WANT_X509_LOOKUP:
10952 case SSL_ERROR_SSL:
10953 case SSL_ERROR_ZERO_RETURN:
10958 #endif /* CK_SSL */
10959 send(csocket,(SENDARG2TYPE)obuf,3,0);
10969 if (ssl_ftp_active_flag) {
10971 rc = SSL_write(ssl_ftp_con,obuf,3);
10972 error = SSL_get_error(ssl_ftp_con,rc);
10974 case SSL_ERROR_NONE:
10976 case SSL_ERROR_WANT_WRITE:
10977 case SSL_ERROR_WANT_READ:
10978 signal(SIGINT,oldintr);
10980 case SSL_ERROR_SYSCALL:
10981 if (rc == 0) { /* EOF */
10985 int gle = GetLastError();
10989 case SSL_ERROR_WANT_X509_LOOKUP:
10990 case SSL_ERROR_SSL:
10991 case SSL_ERROR_ZERO_RETURN:
10996 #endif /* CK_SSL */
10997 send(csocket,(SENDARG2TYPE)obuf,3,0);
11007 signal(SIGINT,oldintr);
11009 debug(F101,"ftp getreply EOF","",ftpcode);
11017 "Service not available, connection closed by server\n");
11020 signal(SIGINT,oldintr);
11022 debug(F101,"ftp getreply EOF","",ftpcode);
11025 if (n == 0) { /* First digit */
11026 n = c; /* Save it */
11030 !ssl_ftp_active_flag &&
11031 #endif /* CK_SSL */
11032 !ibuf[0] && (n == '6' || continuation)) {
11033 if (c != '\r' && dig > 4)
11038 !ssl_ftp_active_flag &&
11039 #endif /* CK_SSL */
11040 !ibuf[0] && dig == 1 && vbm)
11041 printf("Unauthenticated reply received from server:\n");
11046 if ((!dpyactive || ftp_deb) && /* Don't mess up xfer display */
11049 (ftp_deb || ((vbm || (!auth && n == '5')) &&
11050 (dig > 4 || ( dig <= 4 && !isdigit(c) && ftpcode == 0
11054 if (ftp_prx && (dig == 1 || (dig == 5 && vbm == 0)))
11055 printf("%s:",ftp_host);
11056 #endif /* FTP_PROXY */
11063 xlatec(0,c,rcs,lcs);
11067 #endif /* NOCSETS */
11074 !ssl_ftp_active_flag &&
11075 #endif /* CK_SSL */
11076 !ibuf[0] && n != '6')
11078 if (dig < 4 && isdigit(c))
11079 ftpcode = ftpcode * 10 + (c - '0');
11080 if (!pflag && ftpcode == 227)
11082 if (dig > 4 && pflag == 1 && isdigit(c))
11085 if (c != '\r' && c != ')')
11092 if (dig == 4 && c == '-' && n != '6') {
11097 if (cp < &ftp_reply_str[FTP_BUFSIZ - 1]) {
11105 Sometimes we need to print the server reply. printlines is nonzero for any
11106 command where the results are sent back on the control connection rather
11107 than the data connection, e.g. STAT. In the TOPS-20 case, each file line
11108 has ftpcode 213. But if you do this with a UNIX server, it sends "213-Start
11109 STAT", <line with ftpcode == 0>, "213-End" or somesuch. So when printlines
11110 is nonzero, we want the 213 lines from TOPS-20 and we DON'T want the 213
11111 lines from UNIX. Further experimentation needed with other servers. Of
11112 course RFC959 is mute as to the format of the server reply.
11114 'printlines' is also true for PWD and BYE.
11116 (printlines && ((ftpcode == 0) || (servertype == SYS_TOPS20)))
11118 /* No, we can't be that clever -- it breaks other things like RPWD... */
11120 (ftpcode != 631 && ftpcode != 632 && ftpcode != 633))
11121 #endif /* COMMENT */
11124 char *r = ftp_reply_str;
11125 *q-- = NUL; /* NUL-terminate */
11126 while (*q < '!' && q > r) /* Strip CR, etc */
11128 if (!ftp_deb && printlines) { /* If printing */
11129 if (ftpcode != 0) /* strip ftpcode if any */
11132 printf("%s\n",r); /* and print */
11136 } else { /* Translating */
11137 xgnbp = r; /* Set up strgetc() */
11138 while ((c0 = xgnbyte(FC_UCS2,rcs,strgetc)) > -1) {
11139 if (xpnbyte(c0,TC_UCS2,lcs,NULL) < 0) { /* (xprintc) */
11140 signal(SIGINT,oldintr);
11146 #endif /* NOCSETS */
11149 debug(F110,"FTP RCVD ",ftp_reply_str,0);
11151 if (fc == GRF_FEAT) { /* Parsing FEAT command response? */
11152 if (count == 0 && n == '2') {
11153 int i; /* (Re)-init server FEATure table */
11154 debug(F100,"ftp getreply clearing feature table","",0);
11155 for (i = 0; i < 16; i++)
11158 parsefeat((char *)ftp_reply_str);
11163 !ssl_ftp_active_flag &&
11164 #endif /* CK_SSL */
11165 !ibuf[0] && n != '6') {
11166 signal(SIGINT,oldintr);
11167 return(getreply(expecteof,lcs,rcs,vbm,auth));
11169 ibuf[0] = obuf[i] = '\0';
11170 if (ftpcode && n == '6')
11171 if (ftpcode != 631 && ftpcode != 632 && ftpcode != 633) {
11172 printf("Unknown reply: %d %s\n", ftpcode, obuf);
11174 } else safe = (ftpcode == 631);
11175 if (obuf[0] /* if there is a string to decode */
11177 && !ssl_ftp_active_flag /* and not SSL/TLS */
11178 #endif /* CK_SSL */
11181 printf("Cannot decode reply:\n%d %s\n", ftpcode, obuf);
11184 #ifndef CK_ENCRYPTION
11185 else if (ftpcode == 632) {
11186 printf("Cannot decrypt %d reply: %s\n", ftpcode, obuf);
11189 #endif /* CK_ENCRYPTION */
11190 #ifdef NOCONFIDENTIAL
11191 else if (ftpcode == 633) {
11192 printf("Cannot decrypt %d reply: %s\n", ftpcode, obuf);
11195 #endif /* NOCONFIDENTIAL */
11197 int len = FTP_BUFSIZ;
11198 if ((kerror = radix_encode((CHAR *)obuf,
11204 printf("Can't decode base 64 reply %d (%s)\n\"%s\"\n",
11205 ftpcode, radix_error(kerror), obuf);
11209 else if (strcmp(auth_type, "SRP") == 0) {
11211 outlen = srp_decode(!safe, (CHAR *)ibuf,
11212 (CHAR *) ibuf, len);
11214 printf("Warning: %d reply %s!\n",
11215 ftpcode, safe ? "modified" : "garbled");
11218 ckstrncpy(&ibuf[outlen], "\r\n",FTP_BUFSIZ-outlen);
11220 printf("%c:", safe ? 'S' : 'P');
11224 #endif /* FTP_SRP */
11226 else if (strcmp(auth_type, "KERBEROS_V4") == 0) {
11228 kerror = krb_rd_safe((CHAR *)ibuf, len,
11233 #endif /* KRB524 */
11239 kerror = krb_rd_priv((CHAR *)ibuf, len,
11245 #endif /* KRB524 */
11251 if (kerror != KSUCCESS) {
11252 printf("%d reply %s! (krb_rd_%s: %s)\n", ftpcode,
11253 safe ? "modified" : "garbled",
11254 safe ? "safe" : "priv",
11255 krb_get_err_text(kerror));
11257 } else if (ftp_msg_data.app_length >= FTP_BUFSIZ - 3) {
11260 printf("reply data too large for buffer\n");
11263 printf("%c:", safe ? 'S' : 'P');
11264 memcpy(ibuf,ftp_msg_data.app_data,
11265 ftp_msg_data.app_length);
11266 ckstrncpy(&ibuf[ftp_msg_data.app_length], "\r\n",
11267 FTP_BUFSIZ - ftp_msg_data.app_length);
11271 #endif /* FTP_KRB4 */
11273 else if (strcmp(auth_type, "GSSAPI") == 0) {
11274 gss_buffer_desc xmit_buf, msg_buf;
11275 OM_uint32 maj_stat, min_stat;
11277 xmit_buf.value = ibuf;
11278 xmit_buf.length = len;
11279 /* decrypt/verify the message */
11281 maj_stat = gss_unseal(&min_stat, gcontext,
11282 &xmit_buf, &msg_buf,
11283 &conf_state, NULL);
11284 if (maj_stat != GSS_S_COMPLETE) {
11285 user_gss_error(maj_stat, min_stat,
11286 "failed unsealing reply");
11289 memcpy(ibuf, msg_buf.value, msg_buf.length);
11290 ckstrncpy(&ibuf[msg_buf.length], "\r\n",
11291 FTP_BUFSIZ-msg_buf.length);
11292 gss_release_buffer(&min_stat,&msg_buf);
11294 printf("%c:", safe ? 'S' : 'P');
11298 #endif /* FTP_GSSAPI */
11299 /* Other auth types go here... */
11301 } else if ((!dpyactive || ftp_deb) && ftp_cmdlin < 2 &&
11302 !xquiet && (vbm || (!auth && (n == '4' || n == '5')))) {
11307 xlatec(0,c,rcs,lcs);
11311 #endif /* NOCSETS */
11314 if (continuation && ftpcode != originalcode) {
11315 if (originalcode == 0)
11316 originalcode = ftpcode;
11322 signal(SIGINT,oldintr);
11323 if (ftpcode == 421 || originalcode == 421) {
11325 if (!xquiet && !ftp_deb)
11326 printf("%s\n",reply_buf);
11328 if ((cancelfile != 0) &&
11330 /* Ultrix 3.0 cc objects violently to this clause */
11331 (oldintr != cmdcancel) &&
11332 #endif /* ULTRIX3 */
11333 (oldintr != SIG_IGN)) {
11335 (*oldintr)(SIGINT);
11339 if ((reply_ptr = ckstrstr(reply_buf, reply_parse))) {
11340 reply_parse = reply_ptr + strlen(reply_parse);
11341 if ((reply_ptr = ckstrpbrk(reply_parse, " \r")))
11344 reply_parse = reply_ptr;
11346 while (*cp < '!' && cp > ftp_reply_str) /* Remove trailing junk */
11348 debug(F111,"ftp getreply",ftp_reply_str,n - '0');
11356 empty(fd_set * mask, int sec)
11358 empty(mask, sec) fd_set * mask; int sec;
11359 #endif /* CK_ANSIC */
11362 t.tv_sec = (long) sec;
11364 debug(F100,"ftp empty calling select...","",0);
11366 x = select(32, (int *)mask, NULL, NULL, &t);
11368 x = select(32, mask, (fd_set *) 0, (fd_set *) 0, &t);
11369 #endif /* INTSELECT */
11370 debug(F101,"ftp empty select","",x);
11373 #else /* BSDSELECT */
11376 empty(mask, cnt, sec) int * mask, sec;
11379 return(select(mask,cnt,0,0,sec*1000));
11381 #endif /* IBMSELECT */
11382 #endif /* BSDSELECT */
11385 cancelsend(sig) int sig; {
11389 printf(" Canceled...\n");
11390 secure_getc(0,1); /* Initialize net input buffers */
11391 debug(F100,"ftp cancelsend caught SIGINT ","",0);
11394 longjmp(sendcancel, 1);
11402 secure_error(char *fmt, ...)
11405 secure_error(fmt, p1, p2, p3, p4, p5)
11406 char *fmt; int p1, p2, p3, p4, p5;
11407 #endif /* CK_ANSIC */
11413 vfprintf(stderr, fmt, ap);
11416 fprintf(stderr, fmt, p1, p2, p3, p4, p5);
11418 fprintf(stderr, "\n");
11422 * Internal form of settype; changes current type in use with server
11423 * without changing our notion of the type for data transfers.
11424 * Used to change to and from ascii for listings.
11427 changetype(newtype, show) int newtype, show; {
11431 if ((newtype == curtype) && typesent++)
11447 rc = ftpcmd("TYPE",s,-1,-1,show);
11448 if (rc == REPLY_COMPLETE)
11452 /* PUT a file. Returns -1 on error, 0 on success, 1 if file skipped */
11456 doftpsend(void * threadinfo)
11458 doftpsend(threadinfo) VOID * threadinfo;
11462 if (threadinfo) { /* Thread local storage... */
11463 TlsSetValue(TlsIndex,threadinfo);
11464 debug(F100, "doftpsend called with threadinfo block","", 0);
11465 } else debug(F100, "doftpsend - threadinfo is NULL", "", 0);
11474 #endif /* CK_LOGIN */
11479 /* debug(F101,"doftpsend","tcp_http_proxy",tcp_http_proxy); */
11481 /* If the connection failed and we are using an HTTP Proxy
11482 * and the reason for the failure was an authentication
11483 * error, then we need to give the user to ability to
11484 * enter a username and password, just like a browser.
11486 * I tried to do all of this within the netopen() call
11487 * but it is much too much work.
11489 while (y != 0 && tcp_http_proxy != NULL ) {
11491 if (tcp_http_proxy_errno == 401 ||
11492 tcp_http_proxy_errno == 407 ) {
11493 char uid[UIDBUFLEN];
11495 struct txtbox tb[2];
11499 tb[0].t_len = UIDBUFLEN;
11500 tb[0].t_lbl = "Proxy Userid: ";
11501 tb[0].t_dflt = NULL;
11505 tb[1].t_lbl = "Proxy Passphrase: ";
11506 tb[1].t_dflt = NULL;
11509 ok = uq_mtxt("Proxy Server Authentication Required\n",
11511 if (ok && uid[0]) {
11512 char * proxy_user, * proxy_pwd;
11514 proxy_user = tcp_http_proxy_user;
11515 proxy_pwd = tcp_http_proxy_pwd;
11517 tcp_http_proxy_user = uid;
11518 tcp_http_proxy_pwd = pwd;
11522 debug(F101,"doftpsend","initconn",y);
11523 memset(pwd,0,PWDSIZ);
11524 tcp_http_proxy_user = proxy_user;
11525 tcp_http_proxy_pwd = proxy_pwd;
11533 #endif /* NOHTTP */
11534 signal(SIGINT, ftpsnd.oldintr);
11536 if (ftpsnd.oldintp)
11537 signal(SIGPIPE, ftpsnd.oldintp);
11538 #endif /* SIGPIPE */
11543 ckThreadEnd(threadinfo);
11548 #endif /* NOHTTP */
11552 ckThreadEnd(threadinfo);
11558 failftpsend(void * threadinfo)
11560 failftpsend(threadinfo) VOID * threadinfo;
11561 #endif /* CK_ANSIC */
11564 if (threadinfo) { /* Thread local storage... */
11565 TlsSetValue(TlsIndex,threadinfo);
11566 debug(F100, "docmdfile called with threadinfo block","", 0);
11567 } else debug(F100, "docmdfile - threadinfo is NULL", "", 0);
11576 #endif /* CK_LOGIN */
11579 ftpsnd.reply = getreply(0,ftpsnd.incs,ftpsnd.outcs,ftp_vbm,0);
11580 debug(F111,"ftp sendrequest getreply","null command",ftpsnd.reply);
11584 if (ssl_ftp_data_active_flag) {
11585 SSL_shutdown(ssl_ftp_data_con);
11586 SSL_free(ssl_ftp_data_con);
11587 ssl_ftp_data_active_flag = 0;
11588 ssl_ftp_data_con = NULL;
11590 #endif /* CK_SSL */
11592 socket_close(data);
11593 #else /* TCPIPLIB */
11594 #ifdef USE_SHUTDOWN
11595 shutdown(data, 1+1);
11596 #endif /* USE_SHUTDOWN */
11598 #endif /* TCPIPLIB */
11602 if (ftpsnd.oldintr)
11603 signal(SIGINT,ftpsnd.oldintr);
11605 if (ftpsnd.oldintp)
11606 signal(SIGPIPE,ftpsnd.oldintp);
11607 #endif /* SIGPIPE */
11610 /* TEST ME IN K95 */
11613 debug(F100,"ftp failftpsend chain to trap()...","",0);
11614 if (ftpsnd.oldintr != SIG_IGN)
11615 (*ftpsnd.oldintr)(SIGINT);
11616 /* NOTREACHED (I hope!) */
11617 debug(F100,"ftp failftpsend return from trap()...","",0);
11624 failftpsend2(void * threadinfo)
11626 failftpsend2(threadinfo) VOID * threadinfo;
11627 #endif /* CK_ANSIC */
11630 if (threadinfo) { /* Thread local storage... */
11631 TlsSetValue(TlsIndex,threadinfo);
11632 debug(F100, "docmdfile called with threadinfo block","", 0);
11633 } else debug(F100, "docmdfile - threadinfo is NULL", "", 0);
11642 #endif /* CK_LOGIN */
11644 debug(F101,"ftp sendrequest canceled","",ftpsnd.bytes);
11647 fpfsecs = gftimer();
11648 #endif /* GFTIMER */
11653 #endif /* PIPESEND */
11654 signal(SIGINT, ftpsnd.oldintr);
11656 if (ftpsnd.oldintp)
11657 signal(SIGPIPE, ftpsnd.oldintp);
11658 #endif /* SIGPIPE */
11663 ckThreadEnd(threadinfo);
11669 if (ssl_ftp_data_active_flag) {
11670 SSL_shutdown(ssl_ftp_data_con);
11671 SSL_free(ssl_ftp_data_con);
11672 ssl_ftp_data_active_flag = 0;
11673 ssl_ftp_data_con = NULL;
11675 #endif /* CK_SSL */
11677 socket_close(data);
11678 #else /* TCPIPLIB */
11679 #ifdef USE_SHUTDOWN
11680 shutdown(data, 1+1);
11681 #endif /* USE_SHUTDOWN */
11683 #endif /* TCPIPLIB */
11689 socket_close(dout);
11690 #else /* TCPIPLIB */
11691 #ifdef USE_SHUTDOWN
11692 shutdown(dout, 1+1);
11693 #endif /* USE_SHUTDOWN */
11695 #endif /* TCPIPLIB */
11697 ftpsnd.reply = getreply(0,ftpsnd.incs,ftpsnd.outcs,ftp_vbm,0);
11702 /* TEST ME IN K95 */
11705 debug(F100,"ftp failftpsend2 chain to trap()...","",0);
11706 if (ftpsnd.oldintr != SIG_IGN)
11707 (*ftpsnd.oldintr)(SIGINT);
11708 /* NOTREACHED (I hope!) */
11709 debug(F100,"ftp failftpsend2 return from trap()...","",0);
11716 doftpsend2(void * threadinfo)
11718 doftpsend2(threadinfo) VOID * threadinfo;
11721 register int c, d = 0;
11722 int n, t, x, notafile, unique = 0;
11726 if (threadinfo) { /* Thread local storage... */
11727 TlsSetValue(TlsIndex,threadinfo);
11728 debug(F100, "doftpsend2 called with threadinfo block","", 0);
11729 } else debug(F100, "doftpsend2 - threadinfo is NULL", "", 0);
11738 #endif /* CK_LOGIN */
11740 buf = ftpsndbuf; /* (not on stack) */
11742 unique = strcmp(ftpsnd.cmd,"STOU") ? 0 : 1;
11743 notafile = sndarray || pipesend;
11746 if (ftpsnd.restart && ((curtype == FTT_BIN) || (alike > 0))) {
11748 changetype(FTT_BIN,0); /* Change to binary */
11750 /* Ask for remote file's size */
11751 x = ftpcmd("SIZE",ftpsnd.remote,ftpsnd.incs,ftpsnd.outcs,ftp_vbm);
11753 if (x == REPLY_COMPLETE) { /* Have ftpsnd.reply */
11754 p = &ftp_reply_str[4]; /* Parse it */
11755 while (isdigit(*p)) {
11756 sendstart = sendstart * 10 + (int)(*p - '0');
11759 if (*p && *p != CR) { /* Bad number */
11760 debug(F110,"doftpsend2 bad size",ftp_reply_str,0);
11761 sendstart = (CK_OFF_T)0;
11762 } else if (sendstart > fsize) { /* Remote file bigger than local */
11763 debug(F110,"doftpsend2 big size",ckfstoa(fsize),sendstart);
11764 sendstart = (CK_OFF_T)0;
11766 /* Local is newer */
11767 debug(F111,"doftpsend2 size",ftpsnd.remote,sendstart);
11768 if (chkmodtime(ftpsnd.local,ftpsnd.remote,0) == 2) {
11769 debug(F110,"doftpsend2 date mismatch",ftp_reply_str,0);
11770 sendstart = (CK_OFF_T)0; /* Send the whole file */
11773 changetype(ftp_typ,0); /* Change back to appropriate type */
11774 if (sendstart > (CK_OFF_T)0) { /* Still restarting? */
11775 if (sendstart == fsize) { /* Same size - no need to send */
11776 debug(F111,"doftpsend2 /restart SKIP",
11777 ckfstoa(fsize),sendstart);
11779 ftpsndret = SKP_RES;
11781 ckThreadEnd(threadinfo);
11785 errno = 0; /* Restart needed, seek to the spot */
11786 if (zfseek((long)sendstart) < 0) {
11787 debug(F111,"doftpsend2 zfseek fails",
11788 ftpsnd.local,sendstart);
11789 fprintf(stderr, "FSEEK: %s: %s\n", ftpsnd.local, ck_errstr());
11794 ckThreadEnd(threadinfo);
11799 debug(F111,"doftpsend2 zfseek ok",ftpsnd.local,sendstart);
11800 x = ftpcmd("REST",ckltoa(sendstart),-1,-1,ftp_vbm);
11801 if (x != REPLY_CONTINUE) {
11806 ckThreadEnd(threadinfo);
11810 ftpsnd.cmd = "STOR";
11813 sendmode = SM_RESEND;
11814 ftpsnd.cmd = "APPE";
11815 #endif /* COMMENT */
11816 /* sendstart = (CK_OFF_T)0; */
11819 #endif /* FTP_RESTART */
11821 if (unique && !stouarg) /* If we know STOU accepts no arg */
11822 ftpsnd.remote = NULL; /* don't include one. */
11824 x = ftpcmd(ftpsnd.cmd, ftpsnd.remote, ftpsnd.incs, ftpsnd.outcs, ftp_vbm);
11825 debug(F111,"doftpsend2 ftpcode",ftpsnd.cmd,ftpcode);
11826 debug(F101,"doftpsend2 ftpcmd","",x);
11828 if (x != REPLY_PRELIM && unique) {
11830 RFC959 says STOU does not take an argument. But every FTP server
11831 I've encountered but one accepts the arg and constructs the unique
11832 name from it, which is better than making up a totally random name
11833 for the file, which is what RFC959 calls for. Especially because
11834 there is no way for the client to find out the name chosen by the
11835 server. So we try STOU with the argument first, which works with
11836 most servers, and if it fails we retry it without the arg, for
11837 the benefit of the one picky server that is not "liberal in what
11838 it accepts" UNLESS the first STOU got a 502 code ("not implemented")
11839 which means STOU is not accepted, period.
11841 if ((x == 5) && stouarg && (ftpcode != 502)) {
11842 x = ftpcmd(ftpsnd.cmd,NULL,ftpsnd.incs,ftpsnd.outcs,ftp_vbm);
11843 if (x == REPLY_PRELIM) /* If accepted */
11844 stouarg = 0; /* flag no STOU arg for this server */
11847 if (x != REPLY_PRELIM) {
11848 signal(SIGINT, ftpsnd.oldintr);
11850 if (ftpsnd.oldintp)
11851 signal(SIGPIPE, ftpsnd.oldintp);
11852 #endif /* SIGPIPE */
11853 debug(F101,"doftpsend2 not REPLY_PRELIM","",x);
11858 #endif /* PIPESEND */
11861 ckThreadEnd(threadinfo);
11865 debug(F100,"doftpsend2 getting data connection...","",0);
11866 dout = dataconn(ftpsnd.lmode); /* Get data connection */
11867 debug(F101,"doftpsend2 dataconn","",dout);
11869 failftpsend2(threadinfo);
11871 ckThreadEnd(threadinfo);
11875 /* Initialize per-file stats */
11876 ffc = (CK_OFF_T)0; /* Character counter */
11877 cps = oldcps = 0L; /* Thruput */
11880 rftimer(); /* reset f.p. timer */
11881 #endif /* GFTIMER */
11884 ftpsnd.oldintp = signal(SIGPIPE, SIG_IGN);
11885 #endif /* SIGPIPE */
11886 debug(F101,"doftpsend2 curtype","",curtype);
11888 case FTT_BIN: /* Binary mode */
11893 This is because VMS zxin() is C-Library fread()
11894 but the file was opened with zopeni(), which is RMS.
11896 while (((c = zminchar()) > -1) && !cancelfile) {
11898 if (zzout(dout,c) < 0)
11902 while ((n = zxin(ZIFILE,buf,FTP_BUFSIZ - 1)) > 0 && !cancelfile) {
11905 debug(F111,"doftpsend2 zxin",ckltoa(n),ffc);
11906 ckhexdump("doftpsend2 zxin",buf,16);
11908 if (ssl_ftp_data_active_flag) {
11909 for (bufp = buf; n > 0; n -= d, bufp += d) {
11910 if ((d = SSL_write(ssl_ftp_data_con, bufp, n)) <= 0)
11914 if (fdispla != XYFD_B) {
11916 ftscreen(SCR_PT,'D',(CK_OFF_T)spackets,NULL);
11920 #endif /* CK_SSL */
11921 for (bufp = buf; n > 0; n -= d, bufp += d) {
11922 if (((d = secure_write(dout, (CHAR *)bufp, n)) <= 0)
11927 if (fdispla != XYFD_B) {
11929 ftscreen(SCR_PT,'D',(CK_OFF_T)spackets,NULL);
11934 #endif /* CK_SSL */
11940 debug(F111,"doftpsend2 XX zxin",ckltoa(n),ffc);
11942 fprintf(stderr, "local: %s: %s\n", ftpsnd.local, ck_errstr());
11943 if (d < 0 || (d = secure_flush(dout)) < 0) {
11944 if (d == -1 && errno && errno != EPIPE)
11950 case FTT_ASC: /* Text mode */
11952 if (ftpsnd.xlate) { /* With translation */
11953 initxlate(ftpsnd.incs,ftpsnd.outcs);
11954 while (!cancelfile) {
11955 if ((c0 = xgnbyte(FC_UCS2,ftpsnd.incs,NULL)) < 0) break;
11956 if ((x = xpnbyte(c0,TC_UCS2,ftpsnd.outcs,xxout)) < 0) break;
11959 #endif /* NOCSETS */
11960 /* Text mode, no translation */
11961 while (((c = zminchar()) > -1) && !cancelfile) {
11969 #endif /* NOCSETS */
11970 if (dout == -1 || (d = secure_flush(dout)) < 0) {
11971 if (d == -1 && errno && errno != EPIPE)
11977 tfc += ffc; /* Total file chars */
11979 fpfsecs = gftimer();
11980 #endif /* GFTIMER */
11981 zclose(ZIFILE); /* Close input file */
11983 if (sndfilter) /* Undo this (it's per file) */
11985 #endif /* PIPESEND */
11988 if (ssl_ftp_data_active_flag) {
11989 SSL_shutdown(ssl_ftp_data_con);
11990 SSL_free(ssl_ftp_data_con);
11991 ssl_ftp_data_active_flag = 0;
11992 ssl_ftp_data_con = NULL;
11994 #endif /* CK_SSL */
11997 socket_close(dout); /* Close data connection */
11998 #else /* TCPIPLIB */
11999 #ifdef USE_SHUTDOWN
12000 shutdown(dout, 1+1);
12001 #endif /* USE_SHUTDOWN */
12003 #endif /* TCPIPLIB */
12004 ftpsnd.reply = getreply(0,ftpsnd.incs,ftpsnd.outcs,ftp_vbm,0);
12005 signal(SIGINT, ftpsnd.oldintr); /* Put back interrupts */
12007 if (ftpsnd.oldintp)
12008 signal(SIGPIPE, ftpsnd.oldintp);
12009 #endif /* SIGPIPE */
12010 if (ftpsnd.reply == REPLY_TRANSIENT || ftpsnd.reply == REPLY_ERROR) {
12011 debug(F101,"doftpsend2 ftpsnd.reply","",ftpsnd.reply);
12014 ckThreadEnd(threadinfo);
12017 } else if (cancelfile) {
12018 debug(F101,"doftpsend2 canceled","",ftpsnd.bytes);
12021 ckThreadEnd(threadinfo);
12025 debug(F101,"doftpsend2 ok","",ftpsnd.bytes);
12028 ckThreadEnd(threadinfo);
12033 sendrequest(cmd, local, remote, xlate, incs, outcs, restart)
12034 char *cmd, *local, *remote; int xlate, incs, outcs, restart;
12036 if (!remote) remote = ""; /* Check args */
12037 if (!*remote) remote = local;
12038 if (!local) local = "";
12039 if (!*local) return(-1);
12040 if (!cmd) cmd = "";
12041 if (!*cmd) cmd = "STOR";
12043 debug(F111,"ftp sendrequest restart",local,restart);
12045 nout = 0; /* Init output buffer count */
12046 ftpsnd.bytes = 0; /* File input byte count */
12051 proxtrans(cmd, local, remote, !strcmp(cmd,"STOU"));
12054 #endif /* FTP_PROXY */
12056 changetype(ftp_typ,0); /* Change type for this file */
12058 ftpsnd.oldintr = NULL; /* Set up interrupt handler */
12059 ftpsnd.oldintp = NULL;
12060 ftpsnd.restart = restart;
12061 ftpsnd.xlate = xlate;
12062 ftpsnd.lmode = "wb";
12064 #ifdef PIPESEND /* Use Kermit API for file i/o... */
12066 char * p = NULL, * q;
12069 if (cmd_quoting && (p = (char *) malloc(n + 1))) {
12071 debug(F110,"sendrequest pipesend filter",sndfilter,0);
12072 zzstring(sndfilter,&p,&n);
12073 debug(F111,"sendrequest pipename",q,n);
12075 printf("?Sorry, send filter + filename too long, %d max.\n",
12081 ckstrncpy(filnam,q,CKMAXPATH+1);
12088 if (sndfilter) /* If sending thru a filter */
12089 pipesend = 1; /* set this for open and i/o */
12090 #endif /* PIPESEND */
12093 debug(F101,"XXX before openi binary","",binary);
12094 debug(F101,"XXX before openi ftp_typ","",ftp_typ);
12097 if (openi(local) == 0) /* Try to open the input file */
12101 debug(F101,"XXX after openi binary","",binary);
12102 debug(F101,"XXX after openi ftp_typ","",ftp_typ);
12104 if (binary != ftp_typ) { /* VMS zopeni() sets binary */
12105 debug(F101,"XXX changing type","",binary);
12107 debug(F101,"XXX after doftptyp","",ftp_typ);
12110 if (displa && fdispla) { /* Update file type display */
12111 ftscreen(SCR_FN,'F',(CK_OFF_T)0,local);
12117 ftpsnd.incs = incs;
12118 ftpsnd.outcs = outcs;
12120 ftpsnd.local = local;
12121 ftpsnd.remote = remote;
12122 ftpsnd.oldintr = signal(SIGINT, cancelsend);
12125 if (cc_execute(ckjaddr(sendcancel), doftpsend, failftpsend) < 0)
12129 if (cc_execute(ckjaddr(sendcancel), doftpsend2, failftpsend2) < 0)
12136 cancelrecv(sig) int sig; {
12140 secure_getc(0,1); /* Initialize net input buffers */
12141 printf(" Canceling...\n");
12142 debug(F100,"ftp cancelrecv caught SIGINT","",0);
12145 if (fp_nml != stdout)
12150 longjmp(recvcancel, 1);
12156 /* Argumentless front-end for secure_getc() */
12160 return(secure_getc(globaldin,0));
12163 /* Returns -1 on failure, 0 on success, 1 if file skipped */
12166 Sets ftpcode < 0 on failure if failure reason is not server reply code:
12167 -1: interrupted by user.
12168 -2: error opening or writing output file (reason in errno).
12169 -3: failure to make data connection.
12170 -4: network read error (reason in errno).
12173 struct xx_ftprecv {
12181 sig_t oldintr, oldintp;
12188 CK_OFF_T localsize;
12190 static struct xx_ftprecv ftprecv;
12192 static int ftprecvret = 0;
12196 failftprecv(VOID * threadinfo)
12198 failftprecv(threadinfo) VOID * threadinfo;
12199 #endif /* CK_ANSIC */
12202 if (threadinfo) { /* Thread local storage... */
12203 TlsSetValue(TlsIndex,threadinfo);
12204 debug(F100, "docmdfile called with threadinfo block","", 0);
12205 } else debug(F100, "docmdfile - threadinfo is NULL", "", 0);
12215 #endif /* CK_LOGIN */
12218 ftprecv.reply = getreply(0,ftprecv.fcs,ftprecv.rcs,ftp_vbm,0);
12222 if (ssl_ftp_data_active_flag) {
12223 SSL_shutdown(ssl_ftp_data_con);
12224 SSL_free(ssl_ftp_data_con);
12225 ssl_ftp_data_active_flag = 0;
12226 ssl_ftp_data_con = NULL;
12228 #endif /* CK_SSL */
12230 socket_close(data);
12231 #else /* TCPIPLIB */
12232 #ifdef USE_SHUTDOWN
12233 shutdown(data, 1+1);
12234 #endif /* USE_SHUTDOWN */
12236 #endif /* TCPIPLIB */
12240 if (ftprecv.oldintr)
12241 signal(SIGINT, ftprecv.oldintr);
12246 /* TEST ME IN K95 */
12249 debug(F100,"ftp failftprecv chain to trap()...","",0);
12250 if (ftprecv.oldintr != SIG_IGN)
12251 (*ftprecv.oldintr)(SIGINT);
12252 /* NOTREACHED (I hope!) */
12253 debug(F100,"ftp failftprecv return from trap()...","",0);
12261 doftprecv(VOID * threadinfo)
12263 doftprecv(threadinfo) VOID * threadinfo;
12264 #endif /* CK_ANSIC */
12267 if (threadinfo) { /* Thread local storage... */
12268 TlsSetValue(TlsIndex,threadinfo);
12269 debug(F100, "docmdfile called with threadinfo block","", 0);
12270 } else debug(F100, "docmdfile - threadinfo is NULL", "", 0);
12279 #endif /* CK_LOGIN */
12282 if (!out2screen && !ftprecv.pipename) {
12285 local = ftprecv.local;
12288 if ((!dpyactive || ftp_deb))
12290 "Temporary file %s: %s\n", ftprecv.local, ck_errstr());
12291 signal(SIGINT, ftprecv.oldintr);
12295 ckThreadEnd(threadinfo);
12300 #endif /* COMMENT */
12301 changetype((!ftprecv.is_retr) ? FTT_ASC : ftp_typ, 0);
12302 if (initconn()) { /* Initialize the data connection */
12303 signal(SIGINT, ftprecv.oldintr);
12307 ckThreadEnd(threadinfo);
12311 secure_getc(0,1); /* Initialize net input buffers */
12315 ckThreadEnd(threadinfo);
12321 failftprecv2(VOID * threadinfo)
12323 failftprecv2(threadinfo) VOID * threadinfo;
12324 #endif /* CK_ANSIC */
12327 if (threadinfo) { /* Thread local storage... */
12328 TlsSetValue(TlsIndex,threadinfo);
12329 debug(F100, "docmdfile called with threadinfo block","", 0);
12330 } else debug(F100, "docmdfile - threadinfo is NULL", "", 0);
12339 #endif /* CK_LOGIN */
12341 /* Cancel using RFC959 recommended IP,SYNC sequence */
12343 debug(F100,"ftp recvrequest CANCEL","",0);
12345 fpfsecs = gftimer();
12346 #endif /* GFTIMER */
12348 if (ftprecv.oldintp)
12349 signal(SIGPIPE, ftprecv.oldintr);
12350 #endif /* SIGPIPE */
12351 signal(SIGINT, SIG_IGN);
12354 signal(SIGINT, ftprecv.oldintr);
12357 ckThreadEnd(threadinfo);
12361 cancel_remote(ftprecv.din);
12364 if (ftp_timed_out && out2screen && !quiet)
12365 printf("\n?Timed out.\n");
12366 #endif /* FTP_TIMEOUT */
12372 if (ssl_ftp_data_active_flag) {
12373 SSL_shutdown(ssl_ftp_data_con);
12374 SSL_free(ssl_ftp_data_con);
12375 ssl_ftp_data_active_flag = 0;
12376 ssl_ftp_data_con = NULL;
12378 #endif /* CK_SSL */
12380 socket_close(data);
12381 #else /* TCPIPLIB */
12382 #ifdef USE_SHUTDOWN
12383 shutdown(data, 1+1);
12384 #endif /* USE_SHUTDOWN */
12386 #endif /* TCPIPLIB */
12392 debug(F111,"ftp failrecv2 zclose",ftprecv.local,keep);
12394 switch (keep) { /* which is... */
12395 case SET_AUTO: /* AUTO */
12396 if (curtype == FTT_ASC) /* Delete file if TYPE A. */
12399 case SET_OFF: /* DISCARD */
12400 x = 1; /* Delete file, period. */
12402 default: /* KEEP */
12406 x = zdelet(ftprecv.local);
12407 debug(F111,"ftp failrecv2 delete incomplete",ftprecv.local,x);
12412 socket_close(ftprecv.din);
12413 #else /* TCPIPLIB */
12414 #ifdef USE_SHUTDOWN
12415 shutdown(ftprecv.din, 1+1);
12416 #endif /* USE_SHUTDOWN */
12417 close(ftprecv.din);
12418 #endif /* TCPIPLIB */
12420 signal(SIGINT, ftprecv.oldintr);
12425 debug(F100,"FTP failftprecv2 chain to trap()...","",0);
12427 debug(F100,"FTP failftprecv2 PostCtrlCSem()...","",0);
12430 if (ftprecv.oldintr != SIG_IGN)
12431 (*ftprecv.oldintr)(SIGINT);
12432 /* NOTREACHED (I hope!) */
12433 debug(F100,"ftp failftprecv2 return from trap()...","",0);
12440 doftprecv2(VOID * threadinfo)
12442 doftprecv2(threadinfo) VOID * threadinfo;
12443 #endif /* CK_ANSIC */
12446 CK_OFF_T bytes = (CK_OFF_T)0;
12449 ULONG start = 0L, stop;
12451 static char * rcvbuf = NULL;
12452 static int rcvbufsiz = 0;
12454 char newname[CKMAXPATH+1]; /* For file dialog */
12455 #endif /* CK_URL */
12456 extern int adl_ask;
12460 #endif /* FTP_TIMEOUT */
12464 if (threadinfo) { /* Thread local storage... */
12465 TlsSetValue(TlsIndex,threadinfo);
12466 debug(F100, "docmdfile called with threadinfo block","", 0);
12467 } else debug(F100, "docmdfile - threadinfo is NULL", "", 0);
12476 #endif /* CK_LOGIN */
12478 if (ftprecv.recover) { /* Initiate recovery */
12479 x = ftpcmd("REST",ckfstoa(ftprecv.localsize),-1,-1,ftp_vbm);
12480 debug(F111,"ftp reply","REST",x);
12481 if (x == REPLY_CONTINUE) {
12482 ftprecv.lmode = "ab";
12483 rs_len = ftprecv.localsize;
12485 ftprecv.recover = 0;
12488 /* IMPORTANT: No FTP commands can come between REST and RETR! */
12490 debug(F111,"ftp recvrequest recover E",ftprecv.remote,ftprecv.recover);
12492 /* Send the command and get reply */
12493 debug(F110,"ftp recvrequest cmd",ftprecv.cmd,0);
12494 debug(F110,"ftp recvrequest remote",ftprecv.remote,0);
12496 if (ftpcmd(ftprecv.cmd,ftprecv.remote,ftprecv.fcs,ftprecv.rcs,ftp_vbm)
12498 signal(SIGINT, ftprecv.oldintr); /* Bad reply, fail. */
12499 ftprecvret = -1; /* ftpcode is set by ftpcmd() */
12501 ckThreadEnd(threadinfo);
12505 ftprecv.din = dataconn("r"); /* Good reply, open data connection */
12506 globaldin = ftprecv.din; /* Global copy of file descriptor */
12507 if (ftprecv.din == -1) { /* Check for failure */
12508 ftpcode = -3; /* Code for no data connection */
12511 ckThreadEnd(threadinfo);
12516 /* In K95 GUI put up a file box */
12517 if (haveurl && g_url.pth && adl_ask ) { /* Downloading from a URL */
12520 "\r\nIncoming file from FTP server...\r\n\
12521 Please confirm output file specification or supply an alternative:";
12523 x = uq_file(preface, /* K95 GUI: Put up file box. */
12527 ftprecv.local ? ftprecv.local : ftprecv.remote,
12532 ftprecv.local = newname; /* Substitute user's file name */
12533 if (x == 2) /* And append if user said to */
12534 ftprecv.lmode = "ab";
12537 #endif /* CK_URL */
12538 x = 1; /* Output file open OK? */
12539 if (ftprecv.pipename) { /* Command */
12540 x = zxcmd(ZOFILE,ftprecv.pipename);
12541 debug(F111,"ftp recvrequest zxcmd",ftprecv.pipename,x);
12542 } else if (!out2screen) { /* File */
12544 xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
12545 xx.typ = 0; xx.os_specific = NUL; xx.lblopts = 0;
12546 /* Append or New */
12547 xx.dsp = !strcmp(ftprecv.lmode,"ab") ? XYFZ_A : XYFZ_N;
12548 x = zopeno(ZOFILE,ftprecv.local,NULL,&xx);
12549 debug(F111,"ftp recvrequest zopeno",ftprecv.local,x);
12551 if (x < 1) { /* Failure to open output file */
12552 if ((!dpyactive || ftp_deb))
12553 fprintf(stderr, "local(2): %s: %s\n", ftprecv.local, ck_errstr());
12556 ckThreadEnd(threadinfo);
12560 blksize = FTP_BUFSIZ; /* Allocate input buffer */
12562 debug(F101,"ftp recvrequest blksize","",blksize);
12563 debug(F101,"ftp recvrequest rcvbufsiz","",rcvbufsiz);
12565 if (rcvbufsiz < blksize) { /* if necessary */
12570 rcvbuf = (char *)malloc((unsigned)blksize);
12572 debug(F100,"ftp get rcvbuf malloc failed","",0);
12576 #endif /* ENOMEM */
12577 if ((!dpyactive || ftp_deb))
12582 ckThreadEnd(threadinfo);
12586 debug(F101,"ftp get rcvbuf malloc ok","",blksize);
12587 rcvbufsiz = blksize;
12589 debug(F111,"ftp get rcvbufsiz",ftprecv.local,rcvbufsiz);
12591 ffc = (CK_OFF_T)0; /* Character counter */
12592 cps = oldcps = 0L; /* Thruput */
12593 start = gmstimer(); /* Start time (msecs) */
12595 rftimer(); /* Start time (float) */
12596 #endif /* GFTIMER */
12598 debug(F111,"ftp get type",ftprecv.local,curtype);
12599 debug(F101,"ftp recvrequest ftp_dpl","",ftp_dpl);
12601 case FTT_BIN: /* Binary mode */
12602 case FTT_TEN: /* TENEX mode */
12606 c = secure_read(ftprecv.din, rcvbuf, rcvbufsiz);
12608 failftprecv2(threadinfo);
12610 ckThreadEnd(threadinfo);
12616 #ifdef printf /* (What if it isn't?) */
12617 if (out2screen && !ftprecv.pipename) {
12619 for (i = 0; i < c; i++)
12620 printf("%c",rcvbuf[i]);
12622 #endif /* printf */
12628 if (zmchout(rcvbuf[i++]) < 0) {
12639 debug(F100,"ftp recvrequest timeout","",0);
12640 bytes = (CK_OFF_T)-1;
12644 #endif /* FTP_TIMEOUT */
12646 debug(F111,"ftp recvrequest errno",ckitoa(c),errno);
12647 if (c == -1 && errno != EPIPE)
12648 if ((!dpyactive || ftp_deb))
12650 bytes = (CK_OFF_T)-1;
12655 if ((!dpyactive || ftp_deb)) {
12657 p = ftprecv.local ? ftprecv.local : ftprecv.pipename;
12660 "local(3): %s: %s\n", ftprecv.local, ck_errstr());
12663 "%s: short write\n", ftprecv.local);
12668 case FTT_ASC: /* Text mode */
12669 debug(F101,"ftp recvrequest TYPE A xlate","",ftprecv.xlate);
12671 if (ftprecv.xlate) {
12677 #endif /* CK_ANSIC */
12678 debug(F110,"ftp recvrequest (data)","initxlate",0);
12679 initxlate(ftprecv.rcs,ftprecv.fcs); /* (From,To) */
12680 if (ftprecv.pipename) {
12682 debug(F110,"ftp recvrequest ASCII","pipeout",0);
12684 fn = out2screen ? scrnout : putfil;
12685 debug(F110,"ftp recvrequest ASCII",
12686 out2screen ? "scrnout" : "putfil",0);
12689 /* Get byte from net */
12690 c0 = xgnbyte(FC_UCS2,ftprecv.rcs,netgetc);
12692 failftprecv2(threadinfo);
12694 ckThreadEnd(threadinfo);
12700 /* Second byte from net */
12701 c1 = xgnbyte(FC_UCS2,ftprecv.rcs,netgetc);
12703 failftprecv2(threadinfo);
12705 ckThreadEnd(threadinfo);
12712 /* K95: Check whether we need this */
12713 if (fileorder > 0) /* Little Endian */
12714 bytswap(&c0,&c1); /* swap bytes*/
12715 #endif /* COMMENT */
12718 if ( out2screen && /* we're translating to UCS-2 */
12719 !k95stdout && !inserver) /* for the real screen... */
12726 output.bytes[0] = c1;
12727 output.bytes[1] = c0;
12729 VscrnWrtUCS2StrAtt(VCMD,
12740 if ((x = xpnbyte(c0,TC_UCS2,ftprecv.fcs,fn)) < 0) break;
12741 if ((x = xpnbyte(c1,TC_UCS2,ftprecv.fcs,fn)) < 0) break;
12745 #endif /* NOCSETS */
12747 c = secure_getc(ftprecv.din,0);
12751 #endif /* FTP_TIMEOUT */
12753 failftprecv2(threadinfo);
12755 ckThreadEnd(threadinfo);
12759 if (c < 0 || c == EOF)
12762 /* Record format conversion for Unix */
12763 /* SKIP THIS FOR WINDOWS! */
12766 while (c == '\r') {
12768 if ((c = secure_getc(ftprecv.din,0)) != '\n' ||
12771 failftprecv2(threadinfo);
12773 ckThreadEnd(threadinfo);
12777 if (c < 0 || c == EOF)
12789 if (out2screen && !ftprecv.pipename)
12791 printf("%c",(char)c);
12794 #endif /* printf */
12796 if ((d = zmchout(c)) < 0)
12804 if (bare_lfs && (!dpyactive || ftp_deb)) {
12805 printf("WARNING! %d bare linefeeds received in ASCII mode\n",
12807 printf("File might not have transferred correctly.\n");
12809 if (ftprecv.din == -1) {
12810 bytes = (CK_OFF_T)-1;
12813 bytes = (CK_OFF_T)-1;
12817 #endif /* NOCSETS */
12819 if (ftprecv.pipename || !out2screen) {
12820 zclose(ZOFILE); /* Close the file */
12821 debug(F111,"doftprecv2 zclose ftpcode",ftprecv.local,ftpcode);
12822 if (ftpcode < 0) { /* If download failed */
12824 switch (keep) { /* which is... */
12825 case SET_AUTO: /* AUTO */
12826 if (curtype == FTT_ASC) /* Delete file if TYPE A. */
12829 case SET_OFF: /* DISCARD */
12830 x = 1; /* Delete file, period. */
12832 default: /* KEEP */
12836 x = zdelet(ftprecv.local);
12837 debug(F111,"ftp get delete incomplete",ftprecv.local,x);
12841 signal(SIGINT, ftprecv.oldintr);
12843 if (ftprecv.oldintp)
12844 signal(SIGPIPE, ftprecv.oldintp);
12845 #endif /* SIGPIPE */
12848 fpfsecs = gftimer();
12849 #endif /* GFTIMER */
12853 socket_close(ftprecv.din);
12854 #else /* TCPIPLIB */
12855 #ifdef USE_SHUTDOWN
12856 shutdown(ftprecv.din, 1+1);
12857 #endif /* USE_SHUTDOWN */
12858 close(ftprecv.din);
12859 #endif /* TCPIPLIB */
12860 ftprecv.reply = getreply(0,ftprecv.fcs,ftprecv.rcs,ftp_vbm,0);
12861 ftprecvret = ((ftpcode < 0 || ftprecv.reply == REPLY_TRANSIENT ||
12862 ftprecv.reply == REPLY_ERROR) ? -1 : 0);
12864 ckThreadEnd(threadinfo);
12869 recvrequest(cmd, local, remote, lmode, printnames, recover, pipename,
12871 char *cmd, *local, *remote, *lmode, *pipename;
12872 int printnames, recover, xlate, fcs, rcs;
12875 struct _stat stbuf;
12882 debug(F111,"ftp recvrequest cmd",cmd,recover);
12883 debug(F110,"ftp recvrequest local ",local,0);
12884 debug(F111,"ftp recvrequest remote",remote,ftp_typ);
12885 debug(F110,"ftp recvrequest pipename ",pipename,0);
12886 debug(F101,"ftp recvrequest xlate","",xlate);
12887 debug(F101,"ftp recvrequest fcs","",fcs);
12888 debug(F101,"ftp recvrequest rcs","",rcs);
12892 ftprecv.localsize = (CK_OFF_T)0;
12894 if (remfile) { /* See remcfm(), remtxt() */
12896 pipename = remdest;
12899 if (remappd) lmode = "ab";
12903 if (!cmd) cmd = ""; /* Core dump prevention */
12904 if (!remote) remote = "";
12905 if (!lmode) lmode = "";
12907 if (pipename) { /* No recovery for pipes. */
12912 if (!local) /* Output to screen? */
12914 out2screen = !strcmp(local,"-");
12916 debug(F101,"ftp recvrequest out2screen","",out2screen);
12919 if ( ftp_xla && out2screen && !k95stdout && !inserver )
12923 if (out2screen) /* No recovery to screen */
12925 if (!ftp_typ) /* No recovery in text mode */
12927 ftprecv.is_retr = (strcmp(cmd, "RETR") == 0);
12929 if (!ftprecv.is_retr) /* No recovery except for RETRieve */
12933 if (!out2screen && !pipename && ftprecv.is_retr) { /* To real file */
12934 if (recursive && ckstrchr(local,'/')) {
12938 #endif /* COMMENT */
12940 ftprecv.localsize = (CK_OFF_T)0; /* Local file size */
12941 rs_len = (CK_OFF_T)0; /* Recovery point */
12943 debug(F101,"ftp recvrequest recover","",recover);
12944 if (recover) { /* Recovering... */
12945 if (stat(local, &stbuf) < 0) { /* Can't stat local file */
12946 debug(F101,"ftp recvrequest recover stat failed","",errno);
12947 recover = 0; /* So cancel recovery */
12948 } else { /* Have local file info */
12949 ftprecv.localsize = stbuf.st_size; /* Get size */
12950 /* Remote file smaller than local */
12951 if (fsize < ftprecv.localsize) {
12952 debug(F101,"ftp recvrequest recover remote smaller","",fsize);
12953 recover = 0; /* Recovery can't work */
12954 } else if (fsize == ftprecv.localsize) { /* Sizes are equal */
12955 debug(F111,"ftp recvrequest recover equal size",
12956 remote,ftprecv.localsize);
12961 The problem here is that the original partial file never got its date
12962 set, either because FTP DATES was OFF, or because the partial file was
12963 downloaded by some other program that doesn't set local file dates, or
12964 because Kermit only sets the file's date when the download was complete
12965 and successful. In all these cases, the local file has a later time
12968 if (recover) { /* Remote is bigger */
12969 x = chkmodtime(local,remote,0); /* Check file dates */
12970 debug(F111,"ftp recvrequest chkmodtime",remote,x);
12971 if (x != 1) /* Dates must be equal! */
12972 recover = 0; /* If not, get whole file */
12974 #endif /* COMMENT */
12976 debug(F111,"ftp recvrequest recover",remote,recover);
12980 if (proxy && ftprecv.is_retr)
12981 return(proxtrans(cmd, local ? local : remote, remote));
12982 #endif /* FTP_PROXY */
12984 ftprecv.tcrflag = (feol != CR) && ftprecv.is_retr;
12989 ftprecv.recover = recover;
12990 ftprecv.xlate = xlate;
12992 ftprecv.local = local;
12993 ftprecv.remote = remote;
12994 ftprecv.lmode = lmode;
12995 ftprecv.pipename = pipename;
12996 ftprecv.oldintp = NULL;
13000 ftprecv.oldintr = signal(SIGINT, cancelrecv);
13001 if (cc_execute(ckjaddr(recvcancel), doftprecv, failftprecv) < 0)
13005 debug(F111,"ftp recvrequest ftprecvret",remote,ftprecvret);
13006 debug(F111,"ftp recvrequest ftp_timed_out",remote,ftp_timed_out);
13009 #endif /* FTP_TIMEOUT */
13011 if (ftprecvret < 0)
13014 if (cc_execute(ckjaddr(recvcancel), doftprecv2, failftprecv2) < 0)
13020 * Need to start a listen on the data channel before we send the command,
13021 * otherwise the server's connect may fail.
13025 register char *p, *a;
13026 int result, tmpno = 0;
13030 #ifndef NO_PASSIVE_MODE
13031 int a1,a2,a3,a4,p1,p2;
13034 data = socket(AF_INET, SOCK_STREAM, 0);
13037 perror("ftp: socket");
13040 if (ftpcmd("PASV",NULL,0,0,ftp_vbm) != REPLY_COMPLETE) {
13041 printf("Passive mode refused\n");
13043 return(initconn());
13046 Now we have a string of comma-separated one-byte unsigned integer values,
13047 The first four are the an IP address. The fifth is the MSB of the port
13048 number, the sixth is the LSB. From that we can make a sockaddr_in.
13050 if (sscanf(pasv,"%d,%d,%d,%d,%d,%d",&a1,&a2,&a3,&a4,&p1,&p2) != 6) {
13051 printf("Passive mode address scan failure\n");
13055 if (tcp_http_proxy) {
13057 char * agent = "Kermit 95"; /* Default user agent */
13059 char * agent = "C-Kermit";
13061 register struct hostent *hp = 0;
13062 struct servent *destsp;
13063 char host[512], *p, *q;
13065 #ifdef IPTOS_THROUGHPUT
13067 #endif /* IPTOS_THROUGHPUT */
13068 #endif /* IP_TOS */
13077 ckmakxmsg(proxyhost,HTTPCPYL,ckuitoa(a1),".",ckuitoa(a2),
13078 ".",ckuitoa(a3),".",ckuitoa(a4),":",ckuitoa((p1<<8)|p2),
13081 memset((char *)&hisctladdr, 0, sizeof (hisctladdr));
13082 for (p = tcp_http_proxy, q=host; *p != '\0' && *p != ':'; p++, q++)
13086 hisctladdr.sin_addr.s_addr = inet_addr(host);
13087 if (hisctladdr.sin_addr.s_addr != INADDR_NONE) /* 2010-03-29 */
13089 debug(F110,"initconn A",host,0);
13090 hisctladdr.sin_family = AF_INET;
13092 debug(F110,"initconn B",host,0);
13093 hp = gethostbyname(host);
13095 hp = ck_copyhostent(hp); /* make safe copy that won't change */
13096 #endif /* HADDRLIST */
13098 fprintf(stderr, "ftp: %s: Unknown host\n", host);
13105 hisctladdr.sin_family = hp->h_addrtype;
13107 memcpy((char *)&hisctladdr.sin_addr, hp->h_addr_list[0],
13108 sizeof(hisctladdr.sin_addr));
13109 #else /* HADDRLIST */
13110 memcpy((char *)&hisctladdr.sin_addr, hp->h_addr,
13111 sizeof(hisctladdr.sin_addr));
13112 #endif /* HADDRLIST */
13114 data = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
13115 debug(F101,"initconn socket","",data);
13117 perror("ftp: socket");
13129 destsp = getservbyname(p,"tcp");
13131 hisctladdr.sin_port = destsp->s_port;
13133 hisctladdr.sin_port = htons(atoi(p));
13135 hisctladdr.sin_port = htons(80);
13138 debug(F100,"initconn HADDRLIST","",0);
13141 debug(F100,"initconn no HADDRLIST","",0);
13143 #endif /* HADDRLIST */
13144 (connect(data, (struct sockaddr *)&hisctladdr,
13145 sizeof (hisctladdr)) < 0) {
13146 debug(F101,"initconn connect failed","",errno);
13148 if (hp && hp->h_addr_list[1]) {
13149 int oerrno = errno;
13152 "ftp: connect to address %s: ",
13153 inet_ntoa(hisctladdr.sin_addr)
13158 memcpy((char *)&hisctladdr.sin_addr,
13159 hp->h_addr_list[0],
13160 sizeof(hisctladdr.sin_addr));
13161 fprintf(stdout, "Trying %s...\n",
13162 inet_ntoa(hisctladdr.sin_addr));
13164 socket_close(data);
13165 #else /* TCPIPLIB */
13167 #endif /* TCPIPLIB */
13168 data = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
13170 perror("ftp: socket");
13179 #endif /* HADDRLIST */
13180 perror("ftp: connect");
13184 if (http_connect(data,
13185 tcp_http_proxy_agent ?
13186 tcp_http_proxy_agent :
13189 tcp_http_proxy_user,
13190 tcp_http_proxy_pwd,
13195 socket_close(data);
13196 #else /* TCPIPLIB */
13198 #endif /* TCPIPLIB */
13199 perror("ftp: connect");
13204 #endif /* NOHTTP */
13206 data_addr.sin_family = AF_INET;
13207 data_addr.sin_addr.s_addr = htonl((a1<<24)|(a2<<16)|(a3<<8)|a4);
13208 data_addr.sin_port = htons((p1<<8)|p2);
13211 (struct sockaddr *)&data_addr,
13212 sizeof(data_addr)) < 0
13214 perror("ftp: connect");
13218 debug(F100,"initconn connect ok","",0);
13220 #ifdef IPTOS_THROUGHPUT
13221 on = IPTOS_THROUGHPUT;
13222 if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
13223 perror("ftp: setsockopt TOS (ignored)");
13224 #endif /* IPTOS_THROUGHPUT */
13225 #endif /* IP_TOS */
13226 memcpy(&hisdataaddr,&data_addr,sizeof(struct sockaddr_in));
13229 #endif /* NO_PASSIVE_MODE */
13232 memcpy(&data_addr,&myctladdr,sizeof(struct sockaddr_in));
13234 data_addr.sin_port = 0; /* let system pick one */
13237 socket_close(data);
13238 #else /* TCPIPLIB */
13239 #ifdef USE_SHUTDOWN
13240 shutdown(data, 1+1);
13241 #endif /* USE_SHUTDOWN */
13243 #endif /* TCPIPLIB */
13245 data = socket(AF_INET, SOCK_STREAM, 0);
13248 perror("ftp: socket");
13254 if (setsockopt(data,
13261 perror("ftp: setsockopt (reuse address)");
13265 if (bind(data, (struct sockaddr *)&data_addr, sizeof (data_addr)) < 0) {
13266 perror("ftp: bind");
13269 len = sizeof (data_addr);
13270 if (getsockname(data, (struct sockaddr *)&data_addr, &len) < 0) {
13271 perror("ftp: getsockname");
13274 if (listen(data, 1) < 0) {
13275 perror("ftp: listen");
13279 a = (char *)&data_addr.sin_addr;
13280 p = (char *)&data_addr.sin_port;
13281 ckmakxmsg(ftpcmdbuf,FTP_BUFSIZ,"PORT ",
13282 UC(a[0]),",",UC(a[1]),",", UC(a[2]),",", UC(a[3]),",",
13283 UC(p[0]),",", UC(p[1]));
13284 result = ftpcmd(ftpcmdbuf,NULL,0,0,ftp_vbm);
13285 if (result == REPLY_ERROR && sendport) {
13290 return(result != REPLY_COMPLETE);
13295 #ifdef IPTOS_THROUGHPUT
13296 on = IPTOS_THROUGHPUT;
13297 if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
13298 perror("ftp: setsockopt TOS (ignored)");
13304 socket_close(data);
13305 #else /* TCPIPLIB */
13306 #ifdef USE_SHUTDOWN
13307 shutdown(data, 1+1);
13308 #endif /* USE_SHUTDOWN */
13310 #endif /* TCPIPLIB */
13321 if (ssl_ftp_data_con!=NULL) { /* Do SSL */
13322 SSL_free(ssl_ftp_data_con);
13323 ssl_ftp_data_con=NULL;
13325 ssl_ftp_data_con=(SSL *)SSL_new(ssl_ftp_ctx);
13327 SSL_set_fd(ssl_ftp_data_con,data);
13328 SSL_set_verify(ssl_ftp_data_con,ssl_verify_flag,NULL);
13330 SSL_copy_session_id(ssl_ftp_data_con,ssl_ftp_con);
13332 if (ssl_debug_flag) {
13333 fprintf(stderr,"=>START SSL connect on DATA\n");
13336 if (SSL_connect(ssl_ftp_data_con) <= 0) {
13337 static char errbuf[1024];
13338 ckmakmsg(errbuf,1024,"ftp: SSL_connect DATA error: ",
13339 ERR_error_string(ERR_get_error(),NULL),NULL,NULL);
13340 fprintf(stderr,"%s\n", errbuf);
13343 socket_close(data);
13344 #else /* TCPIPLIB */
13345 #ifdef USE_SHUTDOWN
13346 shutdown(data, 1+1);
13347 #endif /* USE_SHUTDOWN */
13349 #endif /* TCPIPLIB */
13354 ssl_ftp_data_active_flag=1;
13356 if (!ssl_certsok_flag && !tls_is_krb5(2)) {
13357 char *subject = ssl_get_subject_name(ssl_ftp_data_con);
13360 if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
13361 debug(F110,"dataconn","[SSL _- FAILED]",0);
13363 ssl_ftp_data_active_flag = 0;
13365 socket_close(data);
13366 #else /* TCPIPLIB */
13367 #ifdef USE_SHUTDOWN
13368 shutdown(data, 1+1);
13369 #endif /* USE_SHUTDOWN */
13371 #endif /* TCPIPLIB */
13376 if (!out2screen && displa && fdispla) {
13377 ftscreen(SCR_TC,0,(CK_OFF_T)0,"Display canceled");
13378 /* fdispla = XYFD_B; */
13382 "Warning: Server didn't provide a certificate on data connection\n",
13383 "Continue with file transfer? (Y/N)",
13385 debug(F110, "dataconn","[SSL - FAILED]",0);
13386 ssl_ftp_data_active_flag = 0;
13388 socket_close(data);
13389 #else /* TCPIPLIB */
13390 #ifdef USE_SHUTDOWN
13391 shutdown(data, 1+1);
13392 #endif /* USE_SHUTDOWN */
13394 #endif /* TCPIPLIB */
13401 if (!out2screen && displa && fdispla == XYFD_C) {
13402 ftscreen(SCR_TC,0,(CK_OFF_T)0,"Display canceled");
13403 /* fdispla = XYFD_B; */
13406 if (ssl_check_server_name(ssl_ftp_data_con,ftp_user_host)) {
13407 debug(F110,"dataconn","[SSL - FAILED]",0);
13408 ssl_ftp_data_active_flag = 0;
13410 socket_close(data);
13411 #else /* TCPIPLIB */
13412 #ifdef USE_SHUTDOWN
13413 shutdown(data, 1+1);
13414 #endif /* USE_SHUTDOWN */
13416 #endif /* TCPIPLIB */
13423 debug(F110,"dataconn","[SSL - OK]",0);
13425 /* This messes up the full screen file transfer display */
13426 ssl_display_connect_details(ssl_ftp_con,0,ssl_verbose_flag);
13427 #endif /* COMMENT */
13429 if (ssl_debug_flag) {
13430 fprintf(stderr,"=>DONE SSL connect on DATA\n");
13435 #endif /* CK_SSL */
13438 dataconn(lmode) char *lmode; {
13442 #endif /* IP_TOS */
13444 static u_int fromlen;
13446 static SOCKOPT_T fromlen;
13449 fromlen = sizeof(hisdataaddr);
13451 #ifndef NO_PASSIVE_MODE
13454 ssl_ftp_data_active_flag=0;
13455 if (ssl_ftp_active_flag &&
13456 (ssl_ftp_proxy || ftp_dpl == FPL_PRV))
13457 return(ssl_dataconn());
13458 #endif /* CK_SSL */
13461 #endif /* NO_PASSIVE_MODE */
13463 s = accept(data, (struct sockaddr *) &hisdataaddr, &fromlen);
13465 perror("ftp: accept");
13467 socket_close(data);
13468 #else /* TCPIPLIB */
13469 #ifdef USE_SHUTDOWN
13470 shutdown(data, 1+1);
13471 #endif /* USE_SHUTDOWN */
13473 #endif /* TCPIPLIB */
13479 socket_close(data);
13480 #else /* TCPIPLIB */
13481 #ifdef USE_SHUTDOWN
13482 shutdown(data, 1+1);
13483 #endif /* USE_SHUTDOWN */
13485 #endif /* TCPIPLIB */
13489 #ifdef IPTOS_THROUGHPUT
13490 tos = IPTOS_THROUGHPUT;
13491 if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
13492 perror("ftp: setsockopt TOS (ignored)");
13493 #endif /* IPTOS_THROUGHPUT */
13494 #endif /* IP_TOS */
13497 ssl_ftp_data_active_flag=0;
13498 if (ssl_ftp_active_flag &&
13499 (ssl_ftp_proxy || ftp_dpl == FPL_PRV))
13500 return(ssl_dataconn());
13501 #endif /* CK_SSL */
13507 pscancel(sig) int sig; {
13512 pswitch(flag) int flag; {
13515 static struct comvars {
13517 char name[MAXHOSTNAMELEN];
13518 struct sockaddr_in mctl;
13519 struct sockaddr_in hctl;
13532 char mi[CKMAXPATH];
13533 char mo[CKMAXPATH];
13538 des_cblock session;
13539 des_key_schedule ftp_sched;
13540 #endif /* FTP_KRB4 */
13542 gss_ctx_id_t gcontext;
13543 #endif /* GSSAPI */
13544 } proxstruct, tmpstruct;
13545 struct comvars *ip, *op;
13548 oldintr = signal(SIGINT, pscancel);
13562 ip->connect = connected;
13563 connected = op->connect;
13565 strncpy(ip->name, ftp_host, MAXHOSTNAMELEN - 1);
13566 ip->name[MAXHOSTNAMELEN - 1] = '\0';
13567 ip->name[strlen(ip->name)] = '\0';
13570 ftp_host = op->name;
13571 ip->hctl = hisctladdr;
13572 hisctladdr = op->hctl;
13573 ip->mctl = myctladdr;
13574 myctladdr = op->mctl;
13581 ip->curtpe = curtype;
13582 curtype = op->curtpe;
13585 ip->sunqe = ftp_usn;
13586 ftp_usn = op->sunqe;
13589 ip->ntflg = ntflag;
13590 ntflag = op->ntflg;
13591 strncpy(ip->nti, ntin, 16);
13592 (ip->nti)[strlen(ip->nti)] = '\0';
13593 strcpy(ntin, op->nti);
13594 strncpy(ip->nto, ntout, 16);
13595 (ip->nto)[strlen(ip->nto)] = '\0';
13596 strcpy(ntout, op->nto);
13597 ip->mapflg = mapflag;
13598 mapflag = op->mapflg;
13599 strncpy(ip->mi, mapin, CKMAXPATH - 1);
13600 (ip->mi)[strlen(ip->mi)] = '\0';
13601 strcpy(mapin, op->mi);
13602 strncpy(ip->mo, mapout, CKMAXPATH - 1);
13603 (ip->mo)[strlen(ip->mo)] = '\0';
13604 strcpy(mapout, op->mo);
13605 ip->authtype = auth_type;
13606 auth_type = op->authtype;
13607 ip->clvl = ftp_cpl;
13608 ftp_cpl = op->clvl;
13609 ip->dlvl = ftp_dpl;
13610 ftp_dpl = op->dlvl;
13616 memcpy(ip->session, ftp_cred.session, sizeof(ftp_cred.session));
13617 memcpy(ftp_cred.session, op->session, sizeof(ftp_cred.session));
13618 memcpy(ip->schedule, ftp_sched, sizeof(ftp_sched));
13619 memcpy(ftp_sched, op->schedule, sizeof(ftp_sched));
13620 #endif /* FTP_KRB4 */
13622 ip->gcontext = gcontext;
13623 gcontext = op->gcontext;
13624 #endif /* GSSAPI */
13625 signal(SIGINT, oldintr);
13628 debug(F101,"pswitch cancelfile B","",cancelfile);
13629 (*oldintr)(SIGINT);
13634 cancelpt(sig) int sig; {
13640 longjmp(ptcancel, 1);
13647 proxtrans(cmd, local, remote, unique) char *cmd, *local, *remote; int unique; {
13649 int secndflag = 0, prox_type, nfnd;
13653 #endif /* BSDSELECT */
13654 sigtype cancelpt();
13656 if (strcmp(cmd, "RETR"))
13659 cmd2 = unique ? "STOU" : "STOR";
13660 if ((prox_type = type) == 0) {
13661 if (servertype == SYS_UNIX && unix_proxy)
13662 prox_type = FTT_BIN;
13664 prox_type = FTT_ASC;
13666 if (curtype != prox_type)
13667 changetype(prox_type, 1);
13668 if (ftpcmd("PASV",NULL,0,0,ftp_vbm) != REPLY_COMPLETE) {
13669 printf("Proxy server does not support third party transfers.\n");
13674 printf("No primary connection\n");
13679 if (curtype != prox_type)
13680 changetype(prox_type, 1);
13682 if (ftpcmd("PORT",pasv,-1,-1,ftp_vbm) != REPLY_COMPLETE) {
13687 /* Replace with calls to cc_execute() */
13688 if (setjmp(ptcancel))
13690 oldintr = signal(SIGINT, cancelpt);
13691 if (ftpcmd(cmd,remote,-1,-1,ftp_vbm) != PRELIM) {
13692 signal(SIGINT, oldintr);
13699 if (ftpcmd(cmd2,local,-1,-1,ftp_vbm) != PRELIM)
13702 getreply(0,-1,-1,ftp_vbm,0);
13704 getreply(0,-1,-1,ftp_vbm,0);
13705 signal(SIGINT, oldintr);
13711 signal(SIGINT, SIG_IGN);
13713 if (strcmp(cmd, "RETR") && !proxy)
13715 else if (!strcmp(cmd, "RETR") && proxy)
13717 if (!cpend && !secndflag) { /* only here if cmd = "STOR" (proxy=1) */
13718 if (ftpcmd(cmd2,local,-1,-1,ftp_vbm) != PRELIM) {
13726 signal(SIGINT, oldintr);
13732 if (!cpend && !secndflag) { /* only if cmd = "RETR" (proxy=1) */
13733 if (ftpcmd(cmd2,local,-1,-1,ftp_vbm) != PRELIM) {
13740 signal(SIGINT, oldintr);
13750 FD_SET(csocket, &mask);
13751 if ((nfnd = empty(&mask, 10)) <= 0) {
13759 #else /* BSDSELECT */
13761 if ((nfnd = empty(&csocket, 1, 10)) <= 0) {
13769 #endif /* IBMSELECT */
13770 #endif /* BSDSELECT */
13771 getreply(0,-1,-1,ftp_vbm,0);
13772 getreply(0,-1,-1,ftp_vbm,0);
13779 signal(SIGINT, oldintr);
13781 #endif /* FTP_PROXY */
13783 #ifdef FTP_SECURITY
13787 /* ck_gss_mech_krb5 is not declared anywhere */
13789 CONST gss_OID_desc * CONST * mech_type;
13790 char *service_name;
13792 { &ck_gss_mech_krb5, "ftp" },
13793 { &ck_gss_mech_krb5, "host" },
13796 /* This matches what is declared above */
13798 CONST gss_OID_desc * CONST * mech_type;
13799 char *service_name;
13801 { &gss_mech_krb5, "ftp" },
13802 { &gss_mech_krb5, "host" },
13804 #endif /* COMMENT */
13807 int n_gss_trials = sizeof(gss_trials)/sizeof(gss_trials[0]);
13808 #endif /* FTP_GSSAPI */
13812 extern int setsafe();
13815 char *service, inst[INST_SZ];
13817 ULONG checksum = (ULONG) getpid();
13818 CHAR out_buf[FTP_BUFSIZ];
13820 #else /* FTP_KRB4 */
13822 CHAR out_buf[FTP_BUFSIZ];
13824 #endif /* FTP_GSSAPI */
13825 #endif /* FTP_KRB4 */
13827 if (ssl_ftp_proxy) /* Do not allow AUTH over SSL proxy */
13831 return(1); /* auth already succeeded */
13833 /* Try each auth type as specified by the end user */
13834 for (j = 0; j < 8 && ftp_auth_type[j] != 0; j++) {
13836 if (ftp_auth_type[j] == FTA_GK5 && ck_gssapi_is_installed()) {
13837 n = ftpcmd("AUTH GSSAPI",NULL,0,0,ftp_vbm);
13838 if (n == REPLY_CONTINUE) {
13839 OM_uint32 maj_stat, min_stat;
13840 gss_name_t target_name;
13841 gss_buffer_desc send_tok, recv_tok, *token_ptr;
13842 char stbuf[FTP_BUFSIZ];
13843 int comcode, trial;
13844 struct gss_channel_bindings_struct chan;
13845 char * realm = NULL;
13848 chan.initiator_addrtype = GSS_C_AF_INET; /* OM_uint32 */
13849 chan.initiator_address.length = 4;
13850 chan.initiator_address.value = &myctladdr.sin_addr.s_addr;
13851 chan.acceptor_addrtype = GSS_C_AF_INET; /* OM_uint32 */
13852 chan.acceptor_address.length = 4;
13853 chan.acceptor_address.value = &hisctladdr.sin_addr.s_addr;
13854 chan.application_data.length = 0;
13855 chan.application_data.value = 0;
13858 printf("GSSAPI accepted as authentication type\n");
13860 realm = ck_krb5_realmofhost(ftp_user_host);
13862 ckmakmsg(tgt,sizeof(tgt),"krbtgt/",realm,"@",realm);
13863 debug(F110,"ftp_auth(GSSAPI) TGT",tgt,0);
13864 if ( krb5_autoget &&
13865 !((ck_krb5_tkt_isvalid(NULL,tgt) > 0) ||
13866 (ck_krb5_is_tgt_valid() > 0)) )
13867 ck_krb5_autoget_TGT(realm);
13870 /* Blob from gss-client */
13871 for (trial = 0; trial < n_gss_trials; trial++) {
13872 /* ftp@hostname first, the host@hostname */
13873 /* the V5 GSSAPI binding canonicalizes this for us... */
13874 ckmakmsg(stbuf,FTP_BUFSIZ,
13875 gss_trials[trial].service_name,
13882 "Authenticating to <%s>...\n", stbuf);
13883 send_tok.value = stbuf;
13884 send_tok.length = strlen(stbuf);
13885 maj_stat = gss_import_name(&min_stat, &send_tok,
13886 gss_nt_service_name,
13889 if (maj_stat != GSS_S_COMPLETE) {
13890 user_gss_error(maj_stat, min_stat, "parsing name");
13891 secure_error("name parsed <%s>\n", stbuf);
13894 token_ptr = GSS_C_NO_BUFFER;
13895 gcontext = GSS_C_NO_CONTEXT; /* structure copy */
13899 fprintf(stderr, "calling gss_init_sec_context\n");
13901 gss_init_sec_context(&min_stat,
13902 GSS_C_NO_CREDENTIAL,
13906 gss_trials[trial].mech_type,
13907 GSS_C_MUTUAL_FLAG |
13908 GSS_C_REPLAY_FLAG |
13910 GSS_C_DELEG_FLAG : 0),
13912 /* channel bindings */
13913 (krb5_d_no_addresses ?
13914 GSS_C_NO_CHANNEL_BINDINGS :
13917 NULL, /* ignore mech type */
13919 NULL, /* ignore ret_flags */
13921 ); /* ignore time_rec */
13923 if (maj_stat != GSS_S_COMPLETE &&
13924 maj_stat != GSS_S_CONTINUE_NEEDED) {
13925 if (trial == n_gss_trials-1)
13926 user_gss_error(maj_stat,
13928 "initializing context"
13930 gss_release_name(&min_stat, &target_name);
13931 /* maybe we missed on the service name */
13934 if (send_tok.length != 0) {
13936 reply_parse = "ADAT="; /* for ftpcmd() later */
13939 radix_encode(send_tok.value,
13947 "Base 64 encoding failed: %s\n",
13948 radix_error(kerror)
13950 goto gss_complete_loop;
13952 comcode = ftpcmd("ADAT",out_buf,-1,-1,0);
13953 if (comcode != REPLY_COMPLETE
13954 && comcode != REPLY_CONTINUE /* (335) */
13956 if (trial == n_gss_trials-1) {
13957 fprintf(stderr, "GSSAPI ADAT failed\n");
13958 /* force out of loop */
13959 maj_stat = GSS_S_FAILURE;
13962 Backoff to the v1 gssapi is still possible.
13963 Send a new AUTH command. If that fails,
13964 terminate the loop.
13966 if (ftpcmd("AUTH GSSAPI",NULL,0,0,ftp_vbm)
13967 != REPLY_CONTINUE) {
13969 "GSSAPI ADAT failed, AUTH restart failed\n");
13970 /* force out of loop */
13971 maj_stat = GSS_S_FAILURE;
13975 if (!reply_parse) {
13977 "No authentication data received from server\n");
13978 if (maj_stat == GSS_S_COMPLETE) {
13980 "...but no more was needed\n");
13981 goto gss_complete_loop;
13983 user_gss_error(maj_stat,
13987 goto gss_complete_loop;
13991 kerror = radix_encode(reply_parse,out_buf,i,&len,
13995 "Base 64 decoding failed: %s\n",
13996 radix_error(kerror));
13997 goto gss_complete_loop;
14000 /* everything worked */
14001 token_ptr = &recv_tok;
14002 recv_tok.value = out_buf;
14003 recv_tok.length = len;
14006 /* get out of loop clean */
14008 trial = n_gss_trials-1;
14009 gss_release_buffer(&min_stat, &send_tok);
14010 gss_release_name(&min_stat, &target_name);
14013 } while (maj_stat == GSS_S_CONTINUE_NEEDED);
14016 if (maj_stat == GSS_S_COMPLETE)
14019 if (maj_stat == GSS_S_COMPLETE) {
14020 printf("GSSAPI authentication succeeded\n");
14021 reply_parse = NULL;
14022 auth_type = "GSSAPI";
14025 fprintf(stderr, "GSSAPI authentication failed\n");
14026 reply_parse = NULL;
14030 fprintf(stderr, "GSSAPI rejected as an authentication type\n");
14031 if (ftpcode == 500 || ftpcode == 502)
14035 #endif /* FTP_GSSAPI */
14037 if (ftp_auth_type[j] == FTA_SRP && ck_srp_is_installed()) {
14038 if (srp_ftp_auth(ftp_user_host,NULL,NULL))
14040 else if (ftpcode == 500 || ftpcode == 502)
14043 #endif /* FTP_SRP */
14045 if (ftp_auth_type[j] == FTA_K4 && ck_krb4_is_installed()) {
14046 n = ftpcmd("AUTH KERBEROS_V4",NULL,0,0,ftp_vbm);
14047 if (n == REPLY_CONTINUE) {
14048 char tgt[4*REALM_SZ+1];
14052 printf("KERBEROS_V4 accepted as authentication type\n");
14053 ckstrncpy(inst, (char *) krb_get_phost(ftp_user_host),INST_SZ);
14054 ckstrncpy(ftp_realm,
14055 (char *)ck_krb4_realmofhost(ftp_user_host),
14059 ckmakmsg(tgt,sizeof(tgt),"krbtgt.",ftp_realm,"@",ftp_realm);
14060 rc = ck_krb4_tkt_isvalid(tgt);
14062 if (rc <= 0 && krb4_autoget)
14063 ck_krb4_autoget_TGT(ftp_realm);
14066 kerror = krb_mk_req(&ftp_tkt,service,inst,ftp_realm,checksum);
14067 if (kerror == KDC_PR_UNKNOWN) {
14069 kerror = krb_mk_req(&ftp_tkt,
14077 fprintf(stderr, "Kerberos V4 krb_mk_req failed: %s\n",
14078 krb_get_err_text(kerror));
14080 kerror = krb_get_cred(service, inst, ftp_realm,&ftp_cred);
14082 fprintf(stderr, "Kerberos V4 krb_get_cred failed: %s\n",
14083 krb_get_err_text(kerror));
14087 rc = des_key_sched(ftp_cred.session, ftp_sched);
14089 printf("?Invalid DES key specified in credentials\r\n");
14090 debug(F110,"ftp_auth",
14091 "invalid DES Key specified in credentials",0);
14092 } else if ( rc == -2 ) {
14093 printf("?Weak DES key specified in credentials\r\n");
14094 debug(F110,"ftp_auth",
14095 "weak DES Key specified in credentials",0);
14096 } else if ( rc != 0 ) {
14097 printf("?DES Key Schedule not set by credentials\r\n");
14098 debug(F110,"ftp_auth",
14099 "DES Key Schedule not set by credentials",0);
14101 reply_parse = "ADAT=";
14103 kerror = radix_encode(ftp_tkt.dat, out_buf, ftp_tkt.length,
14106 fprintf(stderr, "Base 64 encoding failed: %s\n",
14107 radix_error(kerror));
14110 if (i > FTP_BUFSIZ - 6)
14111 printf("?ADAT data too long\n");
14112 if (ftpcmd("ADAT",out_buf,-1,-1,0) !=
14114 fprintf(stderr, "Kerberos V4 authentication failed\n");
14117 if (!reply_parse) {
14119 "No authentication data received from server\n");
14122 i = sizeof(out_buf);
14124 radix_encode(reply_parse, out_buf, 0, &i, RADIX_DECODE);
14126 fprintf(stderr, "Base 64 decoding failed: %s\n",
14127 radix_error(kerror));
14130 kerror = krb_rd_safe(out_buf, i,
14135 #endif /* KRB524 */
14141 fprintf(stderr, "Kerberos V4 krb_rd_safe failed: %s\n",
14142 krb_get_err_text(kerror));
14146 /* fetch the (modified) checksum */
14147 memcpy(&cksum, ftp_msg_data.app_data, sizeof(cksum));
14148 if (ntohl(cksum) == checksum + 1) {
14150 printf("Kerberos V4 authentication succeeded\n");
14151 reply_parse = NULL;
14152 auth_type = "KERBEROS_V4";
14156 "Kerberos V4 mutual authentication failed\n");
14158 reply_parse = NULL;
14163 "KERBEROS_V4 rejected as an authentication type\n");
14164 if (ftpcode == 500 || ftpcode == 502)
14168 #endif /* FTP_KRB4 */
14170 if (ftp_auth_type[j] == FTA_TLS && ck_ssleay_is_installed()) {
14173 ftpcmd("HOST",ftp_user_host,0,0,0);
14176 #endif /* FTPHOST */
14177 n = ftpcmd("AUTH TLS",NULL,0,0,ftp_vbm);
14178 if (n != REPLY_COMPLETE)
14179 n = ftpcmd("AUTH TLS-P",NULL,0,0,ftp_vbm);
14180 if (n == REPLY_COMPLETE) {
14182 printf("TLS accepted as authentication type\n");
14186 if (ssl_ftp_active_flag ) {
14191 fprintf(stderr,"TLS authentication failed\n");
14194 socket_close(csocket);
14195 #else /* TCPIPLIB */
14196 #ifdef USE_SHUTDOWN
14197 shutdown(csocket, 1+1);
14198 #endif /* USE_SHUTDOWN */
14200 #endif /* TCPIPLIB */
14202 if (ftp_hookup(ftp_user_host,ftp_port,0) == NULL)
14207 fprintf(stderr,"TLS rejected as an authentication type\n");
14208 if (ftpcode == 500 || ftpcode == 502)
14212 if (ftp_auth_type[j] == FTA_SSL && ck_ssleay_is_installed()) {
14215 ftpcmd("HOST",ftp_user_host,0,0,0);
14218 #endif /* FTPHOST */
14219 n = ftpcmd("AUTH SSL",NULL,0,0,ftp_vbm);
14220 if (n == REPLY_CONTINUE || n == REPLY_COMPLETE) {
14222 printf("SSL accepted as authentication type\n");
14225 if (ssl_ftp_active_flag) {
14231 fprintf(stderr,"SSL authentication failed\n");
14234 socket_close(csocket);
14235 #else /* TCPIPLIB */
14236 #ifdef USE_SHUTDOWN
14237 shutdown(csocket, 1+1);
14238 #endif /* USE_SHUTDOWN */
14240 #endif /* TCPIPLIB */
14242 if (ftp_hookup(ftp_user_host,ftp_port,0) == NULL)
14247 fprintf(stderr, "SSL rejected as an authentication type\n");
14248 if (ftpcode == 500 || ftpcode == 502)
14252 #endif /* CK_SSL */
14253 /* Other auth types go here ... */
14257 #endif /* FTP_SECURITY */
14261 setprotbuf(unsigned int size)
14263 setprotbuf(size) unsigned int size;
14264 #endif /* CK_ANSIC */
14271 while ((ucbuf = (CHAR *)malloc(actualbuf)) == NULL) {
14277 ucbufsiz = actualbuf - FUDGE_FACTOR;
14278 debug(F101,"setprotbuf ucbufsiz","",ucbufsiz);
14279 if (ucbufsiz < 128) {
14280 printf("WARNING: tiny ucbufsiz: %d\n",ucbufsiz);
14281 } else if (ucbufsiz < 0) {
14282 printf("ERROR: ucbuf allocation failure\n");
14285 maxbuf = actualbuf;
14291 setpbsz(unsigned int size)
14293 setpbsz(size) unsigned int size;
14294 #endif /* CK_ANSIC */
14296 if (!setprotbuf(size)) {
14297 perror("?Error while trying to malloc PROT buffer:");
14300 #endif /* FTP_SRP */
14304 reply_parse = "PBSZ=";
14305 ckmakmsg(ftpcmdbuf,FTP_BUFSIZ,"PBSZ ",
14307 ssl_ftp_active_flag ? "0" :
14308 #endif /* CK_SSL */
14309 ckuitoa(actualbuf),NULL,NULL);
14310 if (ftpcmd(ftpcmdbuf,NULL,0,0,0) != REPLY_COMPLETE) {
14312 printf("?Unable to negotiate PROT buffer size with FTP server\n");
14318 if ((maxbuf = (unsigned int) atol(reply_parse)) > actualbuf)
14319 maxbuf = actualbuf;
14321 maxbuf = actualbuf;
14322 ucbufsiz = maxbuf - FUDGE_FACTOR;
14323 debug(F101,"setpbsz ucbufsiz","",ucbufsiz);
14324 reply_parse = NULL;
14329 cancel_remote(din) int din; {
14330 CHAR buf[FTP_BUFSIZ];
14334 #endif /* BSDSELECT */
14336 int fds[2], fdcnt = 0;
14337 #endif /* IBMSELECT */
14344 debug(F100,"ftp cancel_remote entry","",0);
14346 if (ssl_ftp_active_flag) {
14348 * Send Telnet IP, Telnet DM but do so inline and within the
14359 count = SSL_write(ssl_ftp_con, buf, 4);
14360 debug(F111,"ftp cancel_remote","SSL_write(IAC IP IAC DM)",count);
14361 error = SSL_get_error(ssl_ftp_con,count);
14362 debug(F111,"ftp cancel_remote","SSL_get_error()",error);
14364 case SSL_ERROR_NONE:
14366 case SSL_ERROR_WANT_WRITE:
14367 case SSL_ERROR_WANT_READ:
14368 case SSL_ERROR_SYSCALL:
14371 int gle = GetLastError();
14374 case SSL_ERROR_WANT_X509_LOOKUP:
14375 case SSL_ERROR_SSL:
14376 case SSL_ERROR_ZERO_RETURN:
14382 #endif /* CK_SSL */
14385 * send IAC in urgent mode instead of DM because 4.3BSD places oob mark
14386 * after urgent byte rather than before as is protocol now.
14392 if ((x = send(csocket, (SENDARG2TYPE)buf, 3, MSG_OOB)) != 3)
14394 debug(F101,"ftp cancel_remote send 1","",x);
14396 x = send(csocket,(SENDARG2TYPE)buf,1,0);
14397 debug(F101,"ftp cancel_remote send 2","",x);
14399 x = scommand("ABOR");
14400 debug(F101,"ftp cancel_remote scommand","",x);
14403 FD_SET(csocket, &mask);
14405 FD_SET(din, &mask);
14407 nfnd = empty(&mask, 10);
14408 debug(F101,"ftp cancel_remote empty","",nfnd);
14416 #endif /* FTP_PROXY */
14419 debug(F110,"ftp cancel_remote","D",0);
14420 if (din && FD_ISSET(din, &mask)) {
14421 /* Security: No threat associated with this read. */
14422 /* But you can't simply read the TLS data stream */
14424 if (ssl_ftp_data_active_flag) {
14426 while ((count = SSL_read(ssl_ftp_data_con, buf, FTP_BUFSIZ)) > 0)
14429 #endif /* CK_SSL */
14431 while (recv(din, (SENDARG2TYPE)buf, FTP_BUFSIZ,0) > 0)
14435 debug(F110,"ftp cancel_remote","E",0);
14436 #else /* BSDSELECT */
14444 nfnd = empty(fds, fdcnt, 10);
14445 debug(F101,"ftp cancel_remote empty","",nfnd);
14453 #endif /* FTP_PROXY */
14456 debug(F110,"ftp cancel_remote","D",0);
14457 if (din && select(&din, 1,0,0,1) ) {
14459 if (ssl_ftp_data_active_flag) {
14461 while ((count = SSL_read(ssl_ftp_data_con, buf, FTP_BUFSIZ)) > 0)
14464 #endif /* CK_SSL */
14466 while (recv(din, (SENDARG2TYPE)buf, FTP_BUFSIZ,0) > 0)
14470 debug(F110,"ftp cancel_remote","E",0);
14471 #else /* IBMSELECT */
14472 Some form of select is required.
14473 #endif /* IBMSELECT */
14474 #endif /* BSDSELECT */
14475 if (getreply(0,-1,-1,ftp_vbm,0) == REPLY_ERROR && ftpcode == 552) {
14476 debug(F110,"ftp cancel_remote","F",0);
14477 /* 552 needed for NIC style cancel */
14478 getreply(0,-1,-1,ftp_vbm,0);
14479 debug(F110,"ftp cancel_remote","G",0);
14481 debug(F110,"ftp cancel_remote","H",0);
14482 getreply(0,-1,-1,ftp_vbm,0);
14483 debug(F110,"ftp cancel_remote","I",0);
14490 fts_dpl(x) int x; {
14493 || !ck_crypt_is_installed()
14498 printf("?Cannot set protection level to PRIVATE\n");
14501 printf("?Cannot set protection level to SAFE\n");
14509 if (x == FPL_SAF &&
14510 (!strcmp(auth_type,"SSL") || !strcmp(auth_type,"TLS"))) {
14511 printf("Cannot set protection level to safe\n");
14514 #endif /* CK_SSL */
14515 /* Start with a PBSZ of 1 meg */
14516 if (x != FPL_CLR) {
14517 if (setpbsz(DEFAULT_PBSZ) < 0)
14520 y = ftpcmd(x == FPL_CLR ? "PROT C" :
14521 (x == FPL_SAF ? "PROT S" : "PROT P"), NULL, 0, 0,ftp_vbm);
14522 if (y == REPLY_COMPLETE) {
14530 fts_cpl(x) int x; {
14533 || !ck_crypt_is_installed()
14538 printf("?Cannot set protection level to PRIVATE\n");
14541 printf("?Cannot set protection level to SAFE\n");
14547 if (x == FPL_CLR) {
14548 y = ftpcmd("CCC",NULL,0,0,ftp_vbm);
14549 if (y == REPLY_COMPLETE) {
14561 user_gss_error(maj_stat, min_stat, s)
14562 OM_uint32 maj_stat, min_stat;
14565 /* a lot of work just to report the error */
14566 OM_uint32 gmaj_stat, gmin_stat, msg_ctx;
14567 gss_buffer_desc msg;
14570 gmaj_stat = gss_display_status(&gmin_stat, maj_stat,
14576 if ((gmaj_stat == GSS_S_COMPLETE)||
14577 (gmaj_stat == GSS_S_CONTINUE_NEEDED)) {
14578 fprintf(stderr, "GSSAPI error major: %s\n",
14580 gss_release_buffer(&gmin_stat, &msg);
14582 if (gmaj_stat != GSS_S_CONTINUE_NEEDED)
14587 gmaj_stat = gss_display_status(&gmin_stat, min_stat,
14593 if ((gmaj_stat == GSS_S_COMPLETE)||
14594 (gmaj_stat == GSS_S_CONTINUE_NEEDED)) {
14595 fprintf(stderr, "GSSAPI error minor: %s\n", (char*)msg.value);
14596 gss_release_buffer(&gmin_stat, &msg);
14598 if (gmaj_stat != GSS_S_CONTINUE_NEEDED)
14601 fprintf(stderr, "GSSAPI error: %s\n", s);
14603 #endif /* FTP_GSSAPI */
14611 #endif /* HPUX5WINTCP */
14612 #endif /* datageneral */
14613 #endif /* NOMHHOST */
14616 static struct in_addr inaddrx;
14617 #endif /* INADDRX */
14620 ftp_hookup(host, port, tls) char * host; int port; int tls; {
14621 register struct hostent *hp = 0;
14623 #ifdef IPTOS_THROUGHPUT
14625 #endif /* IPTOS_THROUGHPUT */
14626 #endif /* IP_TOS */
14629 static char hostnamebuf[MAXHOSTNAMELEN];
14630 char hostname[MAXHOSTNAMELEN] /* , *p, *q */ ;
14639 debug(F111,"ftp_hookup",host,port);
14642 if (tcp_http_proxy) {
14643 struct servent *destsp;
14646 ckmakmsg(proxyhost,HTTPCPYL,host,":",ckuitoa(port),NULL);
14647 for (p = tcp_http_proxy, q = hostname;
14648 *p != '\0' && *p != ':';
14659 destsp = getservbyname(p,"tcp");
14661 cport = ntohs(destsp->s_port);
14667 #endif /* NOHTTP */
14669 ckstrncpy(hostname,host,MAXHOSTNAMELEN);
14672 memset((char *)&hisctladdr, 0, sizeof (hisctladdr));
14673 hisctladdr.sin_addr.s_addr = inet_addr(host);
14674 if (hisctladdr.sin_addr.s_addr != INADDR_NONE) /* 2010-03-29 */
14676 debug(F110,"ftp hookup A",hostname,0);
14677 hisctladdr.sin_family = AF_INET;
14678 ckstrncpy(hostnamebuf, hostname, MAXHOSTNAMELEN);
14680 debug(F110,"ftp hookup B",hostname,0);
14681 hp = gethostbyname(hostname);
14683 hp = ck_copyhostent(hp); /* make safe copy that won't change */
14684 #endif /* HADDRLIST */
14686 fprintf(stderr, "ftp: %s: Unknown host\n", host);
14691 return((char *) 0);
14693 hisctladdr.sin_family = hp->h_addrtype;
14695 memcpy((char *)&hisctladdr.sin_addr, hp->h_addr_list[0],
14696 sizeof(hisctladdr.sin_addr));
14697 #else /* HADDRLIST */
14698 memcpy((char *)&hisctladdr.sin_addr, hp->h_addr,
14699 sizeof(hisctladdr.sin_addr));
14700 #endif /* HADDRLIST */
14701 ckstrncpy(hostnamebuf, hp->h_name, MAXHOSTNAMELEN);
14703 debug(F110,"ftp hookup C",hostnamebuf,0);
14704 ftp_host = hostnamebuf;
14705 s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
14706 debug(F101,"ftp hookup socket","",s);
14708 perror("ftp: socket");
14715 hisctladdr.sin_port = htons(cport);
14719 printf("hisctladdr=%d\n",sizeof(hisctladdr));
14720 printf("hisctladdr.sin_addr=%d\n",sizeof(hisctladdr.sin_addr));
14721 printf("sockaddr_in=%d\n",sizeof(struct sockaddr_in));
14722 printf("hisctladdr.sin_addr.s_addr=%d\n",sizeof(hisctladdr.sin_addr.s_addr));
14723 #endif /* COMMENT */
14726 debug(F100,"ftp hookup HADDRLIST","",0);
14729 debug(F100,"ftp hookup no HADDRLIST","",0);
14731 #endif /* HADDRLIST */
14732 (connect(s, (struct sockaddr *)&hisctladdr, sizeof (hisctladdr)) < 0) {
14733 debug(F101,"ftp hookup connect failed","",errno);
14735 if (hp && hp->h_addr_list[1]) {
14736 int oerrno = errno;
14738 fprintf(stderr, "ftp: connect to address %s: ",
14739 inet_ntoa(hisctladdr.sin_addr));
14741 perror((char *) 0);
14743 memcpy((char *)&hisctladdr.sin_addr,
14744 hp->h_addr_list[0],
14745 sizeof(hisctladdr.sin_addr));
14746 fprintf(stdout, "Trying %s...\n",
14747 inet_ntoa(hisctladdr.sin_addr));
14750 #else /* TCPIPLIB */
14752 #endif /* TCPIPLIB */
14753 s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
14755 perror("ftp: socket");
14764 #endif /* HADDRLIST */
14765 perror("ftp: connect");
14769 debug(F100,"ftp hookup connect ok","",0);
14771 len = sizeof (myctladdr);
14773 if (getsockname(s, (struct sockaddr *)&myctladdr, &len) < 0) {
14774 debug(F101,"ftp hookup getsockname failed","",errno);
14775 perror("ftp: getsockname");
14779 debug(F100,"ftp hookup getsockname ok","",0);
14782 if (tcp_http_proxy) {
14784 char * agent = "Kermit 95"; /* Default user agent */
14786 char * agent = "C-Kermit";
14789 if (http_connect(s,agent,NULL,
14790 tcp_http_proxy_user,
14791 tcp_http_proxy_pwd,
14798 #else /* TCPIPLIB */
14800 #endif /* TCPIPLIB */
14802 while (foo == NULL && tcp_http_proxy != NULL ) {
14804 if (tcp_http_proxy_errno == 401 ||
14805 tcp_http_proxy_errno == 407 ) {
14806 char uid[UIDBUFLEN];
14808 struct txtbox tb[2];
14812 tb[0].t_len = UIDBUFLEN;
14813 tb[0].t_lbl = "Proxy Userid: ";
14814 tb[0].t_dflt = NULL;
14818 tb[1].t_lbl = "Proxy Passphrase: ";
14819 tb[1].t_dflt = NULL;
14822 ok = uq_mtxt("Proxy Server Authentication Required\n",
14825 if (ok && uid[0]) {
14826 char * proxy_user, * proxy_pwd;
14828 proxy_user = tcp_http_proxy_user;
14829 proxy_pwd = tcp_http_proxy_pwd;
14831 tcp_http_proxy_user = uid;
14832 tcp_http_proxy_pwd = pwd;
14834 foo = ftp_hookup(host, port, 0);
14836 debug(F110,"ftp_hookup()",foo,0);
14837 memset(pwd,0,PWDSIZ);
14838 tcp_http_proxy_user = proxy_user;
14839 tcp_http_proxy_pwd = proxy_pwd;
14847 perror("ftp: connect");
14851 ckstrncpy(hostnamebuf, proxyhost, MAXHOSTNAMELEN);
14853 #endif /* NOHTTP */
14860 * If the connection is over an SSL proxy then the
14861 * auth_type will be NULL. However, I'm not sure
14862 * whether we should protect the data channel in
14863 * that case or not.
14866 debug(F100,"ftp hookup use_tls","",0);
14868 debug(F100,"ftp hookup ssl_auth failed","",0);
14876 #endif /* CK_SSL */
14879 #ifdef IPTOS_LOWDELAY
14880 tos = IPTOS_LOWDELAY;
14881 if (setsockopt(csocket, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
14882 perror("ftp: setsockopt TOS (ignored)");
14886 printf("Connected to %s.\n", host);
14888 /* Read greeting from server */
14889 if (getreply(0,ftp_csl,ftp_csr,ftp_vbm,0) > 2) {
14890 debug(F100,"ftp hookup bad reply","",0);
14892 socket_close(csocket);
14893 #else /* TCPIPLIB */
14895 #endif /* TCPIPLIB */
14899 #ifdef SO_OOBINLINE
14903 if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char *)&on,
14905 perror("ftp: setsockopt");
14906 debug(F101,"ftp hookup setsockopt failed","",errno);
14910 debug(F100,"ftp hookup setsockopt ok","",0);
14913 #endif /* SO_OOBINLINE */
14921 debug(F100,"ftp hookup bad","",0);
14924 #else /* TCPIPLIB */
14926 #endif /* TCPIPLIB */
14938 /* The purpose of the initial REST 0 is not clear, but other FTP */
14939 /* clients do it. In any case, failure of this command is not a */
14940 /* reliable indication that the server does not support Restart. */
14944 n = ftpcmd("REST 0",NULL,0,0,0);
14945 if (n == REPLY_COMPLETE)
14949 printf("WARNING: Unable to restore file pointer.\n");
14950 #endif /* COMMENT */
14952 n = ftpcmd("SYST",NULL,0,0,0); /* Get server system type */
14953 if (n == REPLY_COMPLETE) {
14954 register char *cp, c = NUL;
14955 cp = ckstrchr(ftp_reply_str+4,' '); /* Get first word of reply */
14957 cp = ckstrchr(ftp_reply_str+4,'\r');
14961 c = *cp; /* Save this char */
14962 *cp = '\0'; /* Replace it with NUL */
14965 printf("Remote system type is %s.\n",ftp_reply_str+4);
14966 ckstrncpy(ftp_srvtyp,ftp_reply_str+4,SRVNAMLEN);
14967 if (cp) /* Put back saved char */
14970 alike = !ckstrcmp(ftp_srvtyp,myostype,-1,0);
14972 if (!ckstrcmp(ftp_srvtyp,"UNIX",-1,0)) servertype = SYS_UNIX;
14973 else if (!ckstrcmp(ftp_srvtyp,"WIN32",-1,0)) servertype = SYS_WIN32;
14974 else if (!ckstrcmp(ftp_srvtyp,"OS/2",-1,0)) servertype = SYS_WIN32;
14975 else if (!ckstrcmp(ftp_srvtyp,"VMS",-1,0)) servertype = SYS_VMS;
14976 else if (!ckstrcmp(ftp_srvtyp,"DOS",-1,0)) servertype = SYS_DOS;
14977 else if (!ckstrcmp(ftp_srvtyp,"TOPS20",-1,0)) servertype = SYS_TOPS20;
14978 else if (!ckstrcmp(ftp_srvtyp,"TOPS10",-1,0)) servertype = SYS_TOPS10;
14982 if (servertype == SYS_UNIX && proxy) unix_proxy = 1;
14983 #endif /* FTP_PROXY */
14985 if (ftp_cmdlin && ftp_xfermode == XMODE_M)
14986 ftp_typ = binary; /* Type given on command line */
14987 else /* Otherwise set it automatically */
14988 ftp_typ = alike ? FTT_BIN : FTT_ASC;
14989 changetype(ftp_typ,0); /* Change to this type */
14990 g_ftp_typ = ftp_typ; /* Make it the global type */
14992 printf("Default transfer mode is %s\n",
14993 ftp_typ ? "BINARY" : "TEXT (\"ASCII\")"
14995 for (i = 0; i < 16; i++) /* Init server FEATure table */
14998 n = ftpcmd("MODE S",NULL,0,0,0); /* We always send in Stream mode */
15000 if (n != REPLY_COMPLETE)
15001 printf("WARNING: Server does not accept MODE S(TREAM)\n");
15002 #endif /* COMMENT */
15003 n = ftpcmd("STRU F",NULL,0,0,0); /* STRU File (not Record or Page) */
15005 if (n != REPLY_COMPLETE)
15006 printf("WARNING: Server does not accept STRU F(ILE)\n");
15007 #endif /* COMMENT */
15009 n = ftpcmd("FEAT",NULL,0,0,0); /* Ask server about features */
15010 if (n == REPLY_COMPLETE) {
15011 debug(F101,"ftp_init FEAT","",sfttab[0]);
15012 if (deblog || ftp_deb) {
15014 for (i = 1; i < 16 && i < nfeattab; i++) {
15015 debug(F111,"ftp_init FEAT",feattab[i].kwd,sfttab[i]);
15017 printf(" Server %s %s\n",
15018 sfttab[i] ? "supports" : "does not support",
15022 /* Deal with disabled MLST opts here if necessary */
15023 /* But why would it be? */
15031 ftp_login(host) char * host; { /* (also called from ckuusy.c) */
15032 static char ftppass[PASSBUFSIZ]="";
15033 char tmp[PASSBUFSIZ];
15034 char *user = NULL, *pass = NULL, *acct = NULL;
15036 extern char uidbuf[];
15037 extern char pwbuf[];
15038 extern int pwflg, pwcrypt;
15040 debug(F111,"ftp_login",ftp_logname,ftp_log);
15042 if (!ckstrcmp(ftp_logname,"anonymous",-1,0))
15044 if (!ckstrcmp(ftp_logname,"ftp",-1,0))
15048 if (auth_type && !strcmp(auth_type, "SRP")) {
15053 #endif /* FTP_SRP */
15055 user = "anonymous";
15056 if (ftp_tmp) { /* They gave a password */
15058 } else if (ftp_apw) { /* SET FTP ANONYMOUS-PASSWORD */
15060 } else { /* Supply user@host */
15061 ckmakmsg(tmp,PASSBUFSIZ,whoami(),"@",myhost,NULL);
15064 debug(F110,"ftp anonymous",pass,0);
15066 #ifdef USE_RUSERPASS
15067 if (ruserpass(host, &user, &pass, &acct) < 0) {
15071 #endif /* USE_RUSERPASS */
15073 user = ftp_logname;
15075 } else if (uidbuf[0] && (ftp_tmp || pwbuf[0] && pwflg)) {
15079 } else if (pwbuf[0] && pwflg) {
15080 ckstrncpy(ftppass,pwbuf,PASSBUFSIZ);
15083 ck_encrypt((char *)ftppass);
15089 while (user == NULL) {
15090 char *myname, prompt[PROMPTSIZ];
15095 ckmakxmsg(prompt,PROMPTSIZ," Name (",host,":",myname,"): ",
15096 NULL,NULL,NULL,NULL,NULL,NULL,NULL);
15098 ckmakmsg(prompt,PROMPTSIZ," Name (",host,"): ",NULL);
15101 ok = uq_txt(NULL,prompt,1,NULL,tmp,PASSBUFSIZ,NULL,
15102 DEFAULT_UQ_TIMEOUT);
15103 if (!ok || *tmp == '\0')
15106 user = brstrip(tmp);
15109 n = ftpcmd("USER",user,-1,-1,ftp_vbm);
15110 if (n == REPLY_COMPLETE) {
15111 /* determine if we need to send a dummy password */
15112 if (ftpcmd("PWD",NULL,0,0,0) != REPLY_COMPLETE)
15113 ftpcmd("PASS dummy",NULL,0,0,1);
15114 } else if (n == REPLY_CONTINUE) {
15115 #ifdef CK_ENCRYPTION
15117 #endif /* CK_ENCRYPTION */
15119 if (pass == NULL) {
15122 ok = uq_txt(NULL," Password: ",2,NULL,ftppass,PASSBUFSIZ,NULL,
15123 DEFAULT_UQ_TIMEOUT);
15125 pass = brstrip(ftppass);
15128 #ifdef CK_ENCRYPTION
15129 oldftp_cpl = ftp_cpl;
15131 #endif /* CK_ENCRYPTION */
15132 n = ftpcmd("PASS",pass,-1,-1,1);
15133 if (!anonymous && pass) {
15135 while (*p++) *(p-1) = NUL;
15136 makestr(&ftp_tmp,NULL);
15138 #ifdef CK_ENCRYPTION
15139 /* level may have changed */
15140 if (ftp_cpl == FPL_PRV)
15141 ftp_cpl = oldftp_cpl;
15142 #endif /* CK_ENCRYPTION */
15144 if (n == REPLY_CONTINUE) {
15146 if (acct == NULL) {
15147 static char ftpacct[80];
15150 ok = uq_txt(NULL," Account: ",2,NULL,ftpacct,80,NULL,
15151 DEFAULT_UQ_TIMEOUT);
15153 acct = brstrip(ftpacct);
15155 n = ftpcmd("ACCT",acct,-1,-1,ftp_vbm);
15157 if (n != REPLY_COMPLETE) {
15158 fprintf(stderr, "FTP login failed.\n");
15160 doexit(BAD_EXIT,-1);
15163 if (!aflag && acct != NULL) {
15164 ftpcmd("ACCT",acct,-1,-1,ftp_vbm);
15166 makestr(&ftp_logname,user);
15169 /* Unprefixed file management commands go to server */
15170 if (autolocus && !ftp_cmdlin) {
15176 if (anonymous && !quiet) {
15177 printf(" Logged in as anonymous (%s)\n",pass);
15178 memset(pass, 0, strlen(pass));
15181 if (doftpcwd(ftp_rdir,-1) < 1)
15182 doexit(BAD_EXIT,-1);
15188 #endif /* FTP_PROXY */
15200 FD_SET(csocket, &mask);
15201 if ((nfnd = empty(&mask,0)) < 0) {
15207 getreply(0,-1,-1,ftp_vbm,0);
15210 #else /* BSDSELECT */
15214 if ((nfnd = empty(&csocket,1,0)) < 0) {
15220 getreply(0,-1,-1,ftp_vbm,0);
15223 #endif /* IBMSELECT */
15224 #endif /* BSDSELECT */
15225 rc = (ftpcmd("REIN",NULL,0,0,ftp_vbm) == REPLY_COMPLETE);
15232 ftp_rename(from, to) char * from, * to; {
15233 int lcs = -1, rcs = -1;
15237 if (lcs < 0) lcs = fcharset;
15239 if (rcs < 0) rcs = ftp_csr;
15241 #endif /* NOCSETS */
15242 if (ftpcmd("RNFR",from,lcs,rcs,ftp_vbm) == REPLY_CONTINUE) {
15243 return(ftpcmd("RNTO",to,lcs,rcs,ftp_vbm) == REPLY_COMPLETE);
15245 return(0); /* Failure */
15249 ftp_umask(mask) char * mask; {
15251 rc = (ftpcmd("SITE UMASK",mask,-1,-1,1) == REPLY_COMPLETE);
15256 ftp_user(user,pass,acct) char * user, * pass, * acct; {
15257 int n = 0, aflag = 0;
15260 if (!auth_type && ftp_aut) {
15262 if (ck_srp_is_installed()) {
15263 if (srp_ftp_auth( NULL, user, pass)) {
15264 makestr(&pass,srp_pass);
15267 #endif /* FTP_SRP */
15269 n = ftpcmd("USER",user,-1,-1,ftp_vbm);
15270 if (n == REPLY_COMPLETE)
15271 n = ftpcmd("PASS dummy",NULL,0,0,1);
15272 else if (n == REPLY_CONTINUE) {
15273 #ifdef CK_ENCRYPTION
15275 #endif /* CK_ENCRYPTION */
15276 if (pass == NULL || !pass[0]) {
15280 ok = uq_txt(NULL," Password: ",2,NULL,pwd,PWDSIZ,NULL,
15281 DEFAULT_UQ_TIMEOUT);
15283 pass = brstrip(pwd);
15286 #ifdef CK_ENCRYPTION
15287 if ((oldftp_cpl = ftp_cpl) == PROT_S)
15289 #endif /* CK_ENCRYPTION */
15290 n = ftpcmd("PASS",pass,-1,-1,1);
15291 memset(pass, 0, strlen(pass));
15292 #ifdef CK_ENCRYPTION
15293 /* level may have changed */
15294 if (ftp_cpl == PROT_P)
15295 ftp_cpl = oldftp_cpl;
15296 #endif /* CK_ENCRYPTION */
15298 if (n == REPLY_CONTINUE) {
15299 if (acct == NULL || !acct[0]) {
15303 ok = uq_txt(NULL," Account: ",2,NULL,pwd,PWDSIZ,NULL,
15304 DEFAULT_UQ_TIMEOUT);
15308 n = ftpcmd("ACCT",acct,-1,-1,ftp_vbm);
15311 if (n != REPLY_COMPLETE) {
15312 printf("Login failed.\n");
15315 if (!aflag && acct != NULL && acct[0]) {
15316 n = ftpcmd("ACCT",acct,-1,-1,ftp_vbm);
15318 if (n == REPLY_COMPLETE) {
15319 makestr(&ftp_logname,user);
15331 return(auth_type ? auth_type : "NULL");
15344 return("confidential");
15360 return("confidential");
15367 /* remote_files() */
15369 Returns next remote filename on success;
15370 NULL on error or no more files with global rfrc set to:
15372 -2: Server error response to NLST, e.g. file not found
15376 #define FTPNAMBUFLEN CKMAXPATH+1024
15378 /* Check: ckmaxfiles CKMAXOPEN */
15380 #define MLSDEPTH 128 /* Stack of open temp files */
15381 static int mlsdepth = 0; /* Temp file stack depth */
15382 static FILE * tmpfilptr[MLSDEPTH+1] = { NULL, NULL }; /* Temp file pointers */
15383 static char * tmpfilnam[MLSDEPTH+1] = { NULL, NULL }; /* Temp file names */
15386 mlsreset() { /* Reset MGET temp-file stack */
15388 for (i = 0; i <= mlsdepth; i++) {
15389 if (tmpfilptr[i]) {
15390 fclose(tmpfilptr[i]);
15391 tmpfilptr[i] = NULL;
15392 if (tmpfilnam[i]) {
15394 unlink(tmpfilnam[i]);
15396 free(tmpfilnam[i]);
15405 remote_files(int new_query, CHAR * arg, CHAR * pattern, int proxy_switch)
15406 #else /* CK_ANSIC */
15407 remote_files(new_query, arg, pattern, proxy_switch)
15409 CHAR * arg; /* That we send to the server */
15410 CHAR * pattern; /* That we use locally */
15412 #endif /* CK_ANSIC */
15413 /* remote_files */ {
15414 static CHAR buf[FTPNAMBUFLEN];
15415 CHAR *cp, *whicharg;
15416 char * cdto = NULL;
15418 int i, x, forced = 0;
15419 int lcs = 0, rcs = 0, xlate = 0;
15421 debug(F101,"ftp remote_files new_query","",new_query);
15422 debug(F110,"ftp remote_files arg",arg,0);
15423 debug(F110,"ftp remote_files pattern",pattern,0);
15426 if (pattern) /* Treat empty pattern same as NULL */
15429 if (arg) /* Ditto for arg */
15436 if (tmpfilptr[mlsdepth]) {
15437 fclose(tmpfilptr[mlsdepth]);
15438 tmpfilptr[mlsdepth] = NULL;
15440 if (!ftp_deb && !deblog)
15441 unlink(tmpfilnam[mlsdepth]);
15445 if (tmpfilptr[mlsdepth] == NULL) {
15446 extern char * tempdir;
15448 debug(F110,"ftp remote_files tempdir",tempdir,0);
15454 p = getenv("K95TMP");
15456 p = getenv("K2TMP");
15460 p = getenv("CK_TMP");
15462 p = getenv("TMPDIR");
15463 if (!p) p = getenv("TEMP");
15464 if (!p) p = getenv("TMP");
15467 int len = strlen(p);
15468 if (p[len-1] != '/'
15470 && p[len-1] != '\\'
15473 static char foo[CKMAXPATH];
15474 ckstrncpy(foo,p,CKMAXPATH);
15475 ckstrncat(foo,"/",CKMAXPATH);
15479 #else /* OS2ORUNIX */
15481 #endif /* OS2ORUNIX */
15482 #ifdef UNIX /* Systems that have a standard */
15483 p = "/tmp/"; /* temporary directory... */
15489 #endif /* datageneral */
15492 debug(F110,"ftp remote_files p",p,0);
15494 /* Get temp file */
15496 if ((tmpfilnam[mlsdepth] = (char *)malloc(CKMAXPATH+1))) {
15497 ckmakmsg((char *)tmpfilnam[mlsdepth],
15498 CKMAXPATH+1,p,"ckXXXXXX",NULL,NULL);
15500 printf("?Malloc failure: remote_files()\n");
15506 char * tmpfil = mktemp((char *)tmpfilnam[mlsdepth]);
15508 ckstrncpy(tmpfilnam[mlsdepth],tmpfil,CKMAXPATH+1);
15513 x = mkstemp((char *)tmpfilnam[mlsdepth]);
15514 if (x > -1) close(x); /* We just want the name. */
15516 mktemp((char *)tmpfilnam[mlsdepth]);
15517 #endif /* MKSTEMP */
15518 /* if no mktmpnam() the name will just be "ckXXXXXX"... */
15519 #endif /* MKTEMP */
15522 debug(F111,"ftp remote_files tmpfilnam[mlsdepth]",
15523 tmpfilnam[mlsdepth],mlsdepth);
15526 if (proxy_switch) {
15529 #endif /* FTP_PROXY */
15531 debug(F101,"ftp remote_files ftp_xla","",ftp_xla);
15532 debug(F101,"ftp remote_files ftp_csl","",ftp_csl);
15533 debug(F101,"ftp remote_files ftp_csr","",ftp_csr);
15536 xlate = ftp_xla; /* SET FTP CHARACTER-SET-TRANSLATION */
15537 if (xlate) { /* ON? */
15538 lcs = ftp_csl; /* Local charset */
15539 if (lcs < 0) lcs = fcharset;
15540 if (lcs < 0) xlate = 0;
15542 if (xlate) { /* Still ON? */
15543 rcs = ftp_csx; /* Remote (Server) charset */
15544 if (rcs < 0) rcs = ftp_csr;
15545 if (rcs < 0) xlate = 0;
15547 #endif /* NOCSETS */
15549 forced = mgetforced; /* MGET method forced? */
15550 if (!forced || !mgetmethod) /* Not forced... */
15551 mgetmethod = (sfttab[0] && sfttab[SFT_MLST]) ? /* so pick one */
15555 User's Command: Result:
15556 mget /nlst NLST (NULL)
15557 mget /nlst foo NLST foo
15558 mget /nlst *.txt NLST *.txt
15559 mget /nlst /match:*.txt NLST (NULL)
15560 mget /nlst /match:*.txt foo NLST foo
15561 mget /mlsd MLSD (NULL)
15562 mget /mlsd foo MLSD foo
15563 mget /mlsd *.txt MLSD (NULL)
15564 mget /mlsd /match:*.txt MLSD (NULL)
15565 mget /mlsd /match:*.txt foo MLSD foo
15569 if (pattern) { /* Don't simplify this! */
15571 } else if (mgetmethod == SND_MLS) {
15573 whicharg = iswild((char *)arg) ? NULL : arg;
15579 debug(F110,"ftp remote_files mgetmethod",
15580 mgetmethod == SND_MLS ? "MLSD" : "NLST", 0);
15581 debug(F110,"ftp remote_files whicharg",whicharg,0);
15583 x = recvrequest((mgetmethod == SND_MLS) ? "MLSD" : "NLST",
15584 (char *)tmpfilnam[mlsdepth],
15594 if (x < 0) { /* Chosen method wasn't accepted */
15596 if (ftpcode > 500 && ftpcode < 505 && !quiet)
15597 printf("?%s: Not supported by server\n",
15598 mgetmethod == SND_MLS ? "MLSD" : "NLST"
15600 rfrc = -2; /* Fail */
15603 /* Not forced - if MLSD failed, try NLST */
15604 if (mgetmethod == SND_MLS) { /* Server lied about MLST */
15605 sfttab[SFT_MLST] = 0; /* So disable it */
15606 mlstok = 0; /* and */
15607 mgetmethod = SND_NLS; /* try NLST */
15615 if (proxy_switch) {
15618 #endif /* FTP_PROXY */
15619 tmpfilptr[mlsdepth] = fopen((char *)tmpfilnam[mlsdepth], "r");
15621 if (tmpfilptr[mlsdepth]) {
15622 if (!ftp_deb && !deblog)
15623 unlink(tmpfilnam[mlsdepth]);
15627 if (!tmpfilptr[mlsdepth]) {
15628 debug(F110,"ftp remote_files open fail",tmpfilnam[mlsdepth],0);
15629 if ((!dpyactive || ftp_deb))
15630 printf("?Can't find list of remote files, oops\n");
15635 printf("LISTFILE: %s\n",tmpfilnam[mlsdepth]);
15638 buf[FTPNAMBUFLEN-1] = NUL;
15639 buf[FTPNAMBUFLEN-2] = NUL;
15641 /* We have to redo all this because the first time was only for */
15642 /* for getting the file list, now it's for getting each file */
15644 if (arg && mgetmethod == SND_MLS) { /* MLSD */
15645 if (!pattern && iswild((char *)arg)) {
15646 pattern = arg; /* Wild arg is really a pattern */
15650 arg = NULL; /* and not an arg */
15652 if (new_query) { /* Initial query? */
15653 cdto = (char *)arg; /* (nonwild) arg given? */
15657 if (cdto) /* If so, then CD to it */
15663 if (fgets((char *)buf, FTPNAMBUFLEN, tmpfilptr[mlsdepth]) == NULL) {
15664 fclose(tmpfilptr[mlsdepth]);
15665 tmpfilptr[mlsdepth] = NULL;
15668 if (!ftp_deb && !deblog)
15669 unlink(tmpfilnam[mlsdepth]);
15671 if (ftp_deb && !deblog) {
15672 printf("(Temporary file %s NOT deleted)\n",
15673 (char *)tmpfilnam[mlsdepth]);
15675 if (mlsdepth <= 0) { /* EOF at depth 0 */
15676 rfrc = -3; /* means we're done */
15679 printf("POPPING(%d)...\n",mlsdepth-1);
15680 if (tmpfilnam[mlsdepth]) free(tmpfilnam[mlsdepth]);
15683 zchdir(".."); /* <-- Not portable */
15686 if (buf[FTPNAMBUFLEN-1]) {
15687 printf("?BUFFER OVERFLOW -- FTP NLST or MLSD string longer than %d\n",
15690 debug(F101,"remote_files buffer overrun","",FTPNAMBUFLEN);
15693 /* debug(F110,"ftp remote_files buf 1",buf,0); */
15694 if ((cp = (CHAR *)ckstrchr((char *)buf,'\n')) != NULL)
15696 if ((cp = (CHAR *)ckstrchr((char *)buf,'\r')) != NULL)
15698 debug(F110,"ftp remote_files buf",buf,0);
15702 printf("[%s]\n",(char *)buf);
15704 havesize = (CK_OFF_T)-1; /* Initialize file facts... */
15706 makestr(&havemdtm,NULL);
15709 if (mgetmethod == SND_NLS) { /* NLST... */
15711 if (!ckmatch((char *)pattern,p,(servertype == SYS_UNIX),1))
15714 } else { /* MLSD... */
15715 p = parsefacts((char *)buf);
15716 switch (havetype) {
15717 case FTYP_FILE: /* File: Get it if it matches */
15719 if (!ckmatch((char *)pattern,p,(servertype == SYS_UNIX),1))
15723 case FTYP_CDIR: /* Current directory */
15724 case FTYP_PDIR: /* Parent directory */
15725 goto again; /* Skip */
15726 case FTYP_DIR: /* (Sub)Directory */
15727 if (!recursive) /* If not /RECURSIVE */
15728 goto again; /* Skip */
15729 if (mlsdepth < MLSDEPTH) {
15732 printf("RECURSING [%s](%d)...\n",p,mlsdepth);
15733 if (doftpcwd(p,0) > 0) {
15735 if (!ckstrchr(p,'/')) {
15736 /* zmkdir() needs dirsep */
15737 if ((p2 = (char *)malloc((int)strlen(p) + 2))) {
15738 strcpy(p2,p); /* SAFE */
15739 strcat(p2,"/"); /* SAFE */
15747 #endif /* NOMKDIR */
15750 p = (char *)remote_files(1,arg,pattern,0);
15753 printf("?mkdir failed: [%s] Depth=%d\n",
15762 printf("?CWD failed: [%s] Depth=%d\n",p,mlsdepth);
15767 printf("MAX DIRECTORY STACK DEPTH EXCEEDED: %d\n",
15778 debug(F101,"remote_files havesize","",havesize);
15779 debug(F101,"remote_files havetype","",havetype);
15780 debug(F110,"remote_files havemdtm",havemdtm,0);
15781 debug(F110,"remote_files name",p,0);
15787 /* N O T P O R T A B L E !!! */
15789 #if (SIZEOF_SHORT == 4)
15790 typedef unsigned short ftp_uint32;
15791 typedef short ftp_int32;
15793 #if (SIZEOF_INT == 4)
15794 typedef unsigned int ftp_uint32;
15795 typedef int ftp_int32;
15797 #if (SIZEOF_LONG == 4)
15798 typedef ULONG ftp_uint32;
15799 typedef long ftp_int32;
15804 /* Perhaps use these in general, certainly use them for GSSAPI */
15806 #ifndef looping_write
15807 #define ftp_int32 int
15808 #define ftp_uint32 unsigned int
15810 looping_write(fd, buf, len)
15812 register CONST char *buf;
15816 register int wrlen = len;
15818 cc = send(fd, (SENDARG2TYPE)buf, wrlen, 0);
15820 if (errno == EINTR)
15827 } while (wrlen > 0);
15831 #ifndef looping_read
15833 looping_read(fd, buf, len)
15835 register char *buf;
15841 cc = recv(fd, (char *)buf, len,0);
15843 if (errno == EINTR)
15845 return(cc); /* errno is already set */
15846 } else if (cc == 0) {
15856 #endif /* looping_read */
15862 secure_putbyte(fd, c) int fd; CHAR c; {
15866 if (nout == (maxbuf ? maxbuf : actualbuf) - FUDGE_FACTOR) {
15868 if (!ftpissecure())
15869 ret = send(fd, (SENDARG2TYPE)ucbuf,
15870 (maxbuf ? maxbuf : actualbuf) - FUDGE_FACTOR, 0);
15872 ret = secure_putbuf(fd,
15874 (maxbuf ? maxbuf : actualbuf) - FUDGE_FACTOR
15880 #endif /* COMMENT */
15884 * -1 on error (errno set)
15885 * -2 on security error
15888 secure_flush(fd) int fd; {
15894 if (!ftpissecure()) {
15895 rc = send(fd, (SENDARG2TYPE)ucbuf, nout, 0);
15899 rc = secure_putbuf(fd, ucbuf, nout);
15904 rc = (!ftpissecure()) ? 0 : secure_putbuf(fd, (CHAR *)"", nout = 0);
15907 if (rc > -1 && len > 0 && fdispla != XYFD_B) {
15910 ftscreen(SCR_PT,'D',(CK_OFF_T)spackets,NULL);
15915 #ifdef COMMENT /* (not used) */
15919 * -2 on security error
15923 secure_putc(char c, int fd)
15925 secure_putc(c, fd) char c; int fd;
15926 #endif /* CK_ANSIC */
15927 /* secure_putc */ {
15928 return(secure_putbyte(fd, (CHAR) c));
15930 #endif /* COMMENT */
15934 * -1 on error (errno set)
15935 * -2 on security error
15939 secure_write(int fd, CHAR * buf, unsigned int nbyte)
15941 secure_write(fd, buf, nbyte)
15944 unsigned int nbyte;
15945 #endif /* CK_ANSIC */
15951 if (check_data_connection(fd,1) < 0) {
15955 #endif /* FTP_TIMEOUT */
15957 if (!ftpissecure()) {
15959 if ((ret = send(fd, (SENDARG2TYPE)ucbuf, nout, 0)) < 0)
15963 return(send(fd,(SENDARG2TYPE)buf,nbyte,0));
15965 int ucbuflen = (maxbuf ? maxbuf : actualbuf) - FUDGE_FACTOR;
15968 while (bsent < nbyte) {
15969 int b2cp = ((nbyte - bsent) > (ucbuflen - nout) ?
15970 (ucbuflen - nout) : (nbyte - bsent));
15973 debug(F101,"secure_write ucbuflen","",ucbuflen);
15974 debug(F101,"secure_write ucbufsiz","",ucbufsiz);
15975 debug(F101,"secure_write bsent","",bsent);
15976 debug(F101,"secure_write b2cp","",b2cp);
15979 memcpy(&ucbuf[nout],&buf[bsent],b2cp);
15983 if (nout == ucbuflen) {
15985 ret = secure_putbuf(fd, ucbuf, ucbuflen);
15996 * -1 on error (errno set)
15997 * -2 on security error
16001 secure_putbuf(int fd, CHAR * buf, unsigned int nbyte)
16003 secure_putbuf(fd, buf, nbyte) int fd; CHAR * buf; unsigned int nbyte;
16004 #endif /* CK_ANSIC */
16006 static char *outbuf = NULL; /* output ciphertext */
16007 #ifdef FTP_SECURITY
16008 static unsigned int bufsize = 0; /* size of outbuf */
16009 #endif /* FTP_SECURITY */
16010 ftp_int32 length = 0;
16011 ftp_uint32 net_len = 0;
16013 /* Other auth types go here ... */
16015 if (ssl_ftp_data_active_flag) {
16018 /* there is no need to send an empty buffer when using SSL/TLS */
16022 count = SSL_write(ssl_ftp_data_con, buf, nbyte);
16023 error = SSL_get_error(ssl_ftp_data_con,count);
16025 case SSL_ERROR_NONE:
16027 case SSL_ERROR_WANT_WRITE:
16028 case SSL_ERROR_WANT_READ:
16029 case SSL_ERROR_SYSCALL:
16032 int gle = GetLastError();
16035 debug(F111,"secure_putbuf","SSL_ERROR_SYSCALL",gle);
16038 case SSL_ERROR_WANT_X509_LOOKUP:
16039 case SSL_ERROR_SSL:
16040 case SSL_ERROR_ZERO_RETURN:
16042 SSL_shutdown(ssl_ftp_data_con);
16043 SSL_free(ssl_ftp_data_con);
16044 ssl_ftp_data_active_flag = 0;
16045 ssl_ftp_data_con = NULL;
16047 socket_close(data);
16048 #else /* TCPIPLIB */
16049 #ifdef USE_SHUTDOWN
16050 shutdown(data, 1+1);
16051 #endif /* USE_SHUTDOWN */
16053 #endif /* TCPIPLIB */
16060 #endif /* CK_SSL */
16063 if (ck_srp_is_installed() && (strcmp(auth_type, "SRP") == 0)) {
16064 if (bufsize < nbyte + FUDGE_FACTOR) {
16066 (outbuf = realloc(outbuf, (unsigned) (nbyte + FUDGE_FACTOR))):
16067 (outbuf = malloc((unsigned) (nbyte + FUDGE_FACTOR)))) {
16068 bufsize = nbyte + FUDGE_FACTOR;
16071 secure_error("%s (in malloc of PROT buffer)", ck_errstr());
16076 srp_encode(ftp_dpl == FPL_PRV,
16082 secure_error ("srp_encode failed");
16086 #endif /* FTP_SRP */
16088 if (ck_krb4_is_installed() && (strcmp(auth_type, "KERBEROS_V4") == 0)) {
16089 struct sockaddr_in myaddr, hisaddr;
16091 len = sizeof(myaddr);
16092 if (getsockname(fd, (struct sockaddr*)&myaddr, &len) < 0) {
16093 secure_error("secure_putbuf: getsockname failed");
16096 len = sizeof(hisaddr);
16097 if (getpeername(fd, (struct sockaddr*)&hisaddr, &len) < 0) {
16098 secure_error("secure_putbuf: getpeername failed");
16101 if (bufsize < nbyte + FUDGE_FACTOR) {
16103 (outbuf = realloc(outbuf, (unsigned) (nbyte + FUDGE_FACTOR))):
16104 (outbuf = malloc((unsigned) (nbyte + FUDGE_FACTOR)))) {
16105 bufsize = nbyte + FUDGE_FACTOR;
16108 secure_error("%s (in malloc of PROT buffer)", ck_errstr());
16112 if (ftp_dpl == FPL_PRV) {
16113 length = krb_mk_priv(buf, (CHAR *) outbuf, nbyte,
16119 #endif /* KRB524 */
16124 length = krb_mk_safe(buf, (CHAR *) outbuf, nbyte,
16129 #endif /* KRB524 */
16134 if (length == -1) {
16135 secure_error("krb_mk_%s failed for KERBEROS_V4",
16136 ftp_dpl == FPL_PRV ? "priv" : "safe");
16140 #endif /* FTP_KRB4 */
16142 if (ck_gssapi_is_installed() && (strcmp(auth_type, "GSSAPI") == 0)) {
16143 gss_buffer_desc in_buf, out_buf;
16144 OM_uint32 maj_stat, min_stat;
16147 in_buf.value = buf;
16148 in_buf.length = nbyte;
16149 maj_stat = gss_seal(&min_stat, gcontext,
16150 (ftp_dpl == FPL_PRV), /* confidential */
16156 if (maj_stat != GSS_S_COMPLETE) {
16157 /* generally need to deal */
16158 /* ie. should loop, but for now just fail */
16159 user_gss_error(maj_stat, min_stat,
16160 ftp_dpl == FPL_PRV?
16161 "GSSAPI seal failed":
16162 "GSSAPI sign failed");
16165 if (bufsize < out_buf.length) {
16167 (outbuf = realloc(outbuf, (unsigned) out_buf.length)):
16168 (outbuf = malloc((unsigned) out_buf.length))) {
16169 bufsize = out_buf.length;
16172 secure_error("%s (in malloc of PROT buffer)",
16177 memcpy(outbuf, out_buf.value, length=out_buf.length);
16178 gss_release_buffer(&min_stat, &out_buf);
16180 #endif /* FTP_GSSAPI */
16181 net_len = htonl((ULONG) length);
16182 if (looping_write(fd, (char *)&net_len, 4) == -1)
16184 if (looping_write(fd, outbuf, length) != length)
16190 /* fc = 0 means to get a byte; nonzero means to initialize buffer pointers */
16193 secure_getbyte(fd,fc) int fd,fc; {
16194 /* number of chars in ucbuf, pointer into ucbuf */
16195 static unsigned int nin = 0, bufp = 0;
16209 if (check_data_connection(fd,0) < 0)
16211 #endif /* FTP_TIMEOUT */
16214 if (ssl_ftp_data_active_flag) {
16216 count = SSL_read(ssl_ftp_data_con, ucbuf, ucbufsiz);
16217 error = SSL_get_error(ssl_ftp_data_con,count);
16219 if (error != SSL_ERROR_NONE)
16220 debug(F101,"ftp secure_getbyte error","",error);
16222 debug(F101,"ftp secure_getbyte count","",count);
16225 case SSL_ERROR_NONE:
16227 nin = bufp = count;
16230 if (fdispla != XYFD_B) {
16232 ftscreen(SCR_PT,'D',(CK_OFF_T)rpackets,NULL);
16236 case SSL_ERROR_WANT_WRITE:
16237 case SSL_ERROR_WANT_READ:
16238 case SSL_ERROR_SYSCALL:
16241 int gle = GetLastError();
16244 case SSL_ERROR_WANT_X509_LOOKUP:
16245 case SSL_ERROR_SSL:
16246 case SSL_ERROR_ZERO_RETURN:
16248 nin = bufp = count = 0;
16249 SSL_shutdown(ssl_ftp_data_con);
16250 SSL_free(ssl_ftp_data_con);
16251 ssl_ftp_data_active_flag = 0;
16252 ssl_ftp_data_con = NULL;
16254 socket_close(data);
16255 #else /* TCPIPLIB */
16256 #ifdef USE_SHUTDOWN
16257 shutdown(data, 1+1);
16258 #endif /* USE_SHUTDOWN */
16260 #endif /* TCPIPLIB */
16266 #endif /* CK_SSL */
16268 kerror = looping_read(fd, (char *)&length, sizeof(length));
16269 if (kerror != sizeof(length)) {
16270 secure_error("Couldn't read PROT buffer length: %d/%s",
16272 kerror == -1 ? ck_errstr()
16277 debug(F101,"secure_getbyte length","",length);
16278 debug(F101,"secure_getbyte ntohl(length)","",ntohl(length));
16280 length = (ULONG) ntohl(length);
16281 if (length > maxbuf) {
16282 secure_error("Length (%d) of PROT buffer > PBSZ=%u",
16288 if ((kerror = looping_read(fd, ucbuf, length)) != length) {
16289 secure_error("Couldn't read %u byte PROT buffer: %s",
16291 kerror == -1 ? ck_errstr() : "premature EOF"
16296 /* Other auth types go here ... */
16298 if (strcmp(auth_type, "SRP") == 0) {
16299 if ((nin = bufp = srp_decode (ftp_dpl == FPL_PRV,
16305 secure_error ("srp_encode failed" );
16309 #endif /* FTP_SRP */
16311 if (strcmp(auth_type, "KERBEROS_V4") == 0) {
16312 struct sockaddr_in myaddr, hisaddr;
16314 len = sizeof(myaddr);
16315 if (getsockname(fd, (struct sockaddr*)&myaddr, &len) < 0) {
16316 secure_error("secure_putbuf: getsockname failed");
16319 len = sizeof(hisaddr);
16320 if (getpeername(fd, (struct sockaddr*)&hisaddr, &len) < 0) {
16321 secure_error("secure_putbuf: getpeername failed");
16325 kerror = krb_rd_priv(ucbuf, length, ftp_sched,
16330 #endif /* KRB524 */
16331 &hisaddr, &myaddr, &ftp_msg_data);
16333 kerror = krb_rd_safe(ucbuf, length,
16338 #endif /* KRB524 */
16339 &hisaddr, &myaddr, &ftp_msg_data);
16342 secure_error("krb_rd_%s failed for KERBEROS_V4 (%s)",
16343 ftp_dpl == FPL_PRV ? "priv" : "safe",
16344 krb_get_err_text(kerror));
16347 memcpy(ucbuf,ftp_msg_data.app_data,ftp_msg_data.app_length);
16348 nin = bufp = ftp_msg_data.app_length;
16350 #endif /* FTP_KRB4 */
16352 if (strcmp(auth_type, "GSSAPI") == 0) {
16353 gss_buffer_desc xmit_buf, msg_buf;
16354 OM_uint32 maj_stat, min_stat;
16357 xmit_buf.value = ucbuf;
16358 xmit_buf.length = length;
16359 conf_state = (ftp_dpl == FPL_PRV);
16360 /* decrypt/verify the message */
16361 maj_stat = gss_unseal(&min_stat, gcontext, &xmit_buf,
16362 &msg_buf, &conf_state, NULL);
16363 if (maj_stat != GSS_S_COMPLETE) {
16364 user_gss_error(maj_stat, min_stat,
16365 (ftp_dpl == FPL_PRV)?
16366 "failed unsealing ENC message":
16367 "failed unsealing MIC message");
16370 memcpy(ucbuf, msg_buf.value, nin = bufp = msg_buf.length);
16371 gss_release_buffer(&min_stat, &msg_buf);
16373 #endif /* FTP_GSSAPI */
16374 /* Other auth types go here ... */
16376 /* Update file transfer display */
16379 if (fdispla != XYFD_B) {
16381 ftscreen(SCR_PT,'D',(CK_OFF_T)rpackets,NULL);
16388 return(ucbuf[bufp - nin--]);
16391 /* secure_getc(fd,fc)
16393 * fd = file descriptor for connection.
16394 * fc = 0 to get a character, fc != 0 to initialize buffer pointers.
16396 * c>=0 on success (character value)
16398 * -2 on security error
16399 * -3 on timeout (if built with FTP_TIMEOUT defined)
16402 secure_getc(fd,fc) int fd,fc; { /* file descriptor, function code */
16404 if (!ftpissecure()) {
16405 static unsigned int nin = 0, bufp = 0;
16416 if (check_data_connection(fd,0) < 0) {
16417 debug(F100,"secure_getc TIMEOUT","",0);
16422 #endif /* FTP_TIMEOUT */
16424 nin = bufp = recv(fd,(char *)ucbuf,actualbuf,0);
16425 if ((nin == 0) || (nin == (unsigned int)-1)) {
16426 debug(F111,"secure_getc recv errno",ckitoa(nin),errno);
16427 debug(F101,"secure_getc returns EOF","",EOF);
16431 debug(F101,"ftp secure_getc recv","",nin);
16432 ckhexdump("ftp secure_getc recv",ucbuf,16);
16435 if (fdispla != XYFD_B) {
16437 ftscreen(SCR_PT,'D',(CK_OFF_T)rpackets,NULL);
16440 return(ucbuf[bufp - nin--]);
16442 return(secure_getbyte(fd,fc));
16446 * n>0 on success (n == # of bytes read)
16448 * -1 on error (errno set), only for FPL_CLR
16449 * -2 on security error
16452 secure_read(fd, buf, nbyte) int fd; char *buf; int nbyte; {
16456 debug(F101,"secure_read bytes requested","",nbyte);
16459 for (i = 0; nbyte > 0; nbyte--) {
16460 c = secure_getc(fd,0);
16462 case -9: /* Canceled from keyboard */
16463 debug(F101,"ftp secure_read interrupted","",c);
16466 debug(F101,"ftp secure_read error","",c);
16469 debug(F101,"ftp secure_read EOF","",c);
16475 debug(F101,"ftp secure_read timeout","",c);
16477 #endif /* FTP_TIMEOUT */
16485 #ifdef USE_RUSERPASS
16488 * Copyright (c) 1985 Regents of the University of California.
16489 * All rights reserved.
16491 * Redistribution and use in source and binary forms, with or without
16492 * modification, are permitted provided that the following conditions
16494 * 1. Redistributions of source code must retain the above copyright
16495 * notice, this list of conditions and the following disclaimer.
16496 * 2. Redistributions in binary form must reproduce the above copyright
16497 * notice, this list of conditions and the following disclaimer in the
16498 * documentation and/or other materials provided with the distribution.
16499 * 3. All advertising materials mentioning features or use of this software
16500 * must display the following acknowledgement:
16501 * This product includes software developed by the University of
16502 * California, Berkeley and its contributors.
16503 * 4. Neither the name of the University nor the names of its contributors
16504 * may be used to endorse or promote products derived from this software
16505 * without specific prior written permission.
16507 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
16508 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16509 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16510 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
16511 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
16512 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
16513 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
16514 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
16515 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
16516 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
16521 static char sccsid[] = "@(#)ruserpass.c 5.3 (Berkeley) 3/1/91";
16522 #endif /* not lint */
16524 #ifndef MAXHOSTNAMELEN
16525 #define MAXHOSTNAMELEN 64
16529 static FILE * cfile;
16539 static char tokval[100];
16541 static struct toktab {
16545 "default", DEFAULT,
16547 "password", PASSWD,
16549 "account", ACCOUNT,
16563 while ((c = getc(cfile)) != EOF &&
16564 (c == '\n' || c == '\t' || c == ' ' || c == ','))
16570 while ((c = getc(cfile)) != EOF && c != '"') {
16577 while ((c = getc(cfile)) != EOF
16578 && c != '\n' && c != '\t' && c != ' ' && c != ',') {
16585 if (tokval[0] == 0)
16587 for (t = toktab; t->tokstr; t++)
16588 if (!strcmp(t->tokstr, tokval))
16593 ruserpass(host, aname, apass, aacct)
16594 char *host, **aname, **apass, **aacct;
16596 char *hdir, buf[FTP_BUFSIZ], *tmp;
16597 char myname[MAXHOSTNAMELEN], *mydomain;
16598 int t, i, c, usedefault = 0;
16605 hdir = getenv("HOME");
16608 ckmakmsg(buf,FTP_BUFSIZ,hdir,"/.netrc",NULL,NULL);
16609 cfile = fopen(buf, "r");
16610 if (cfile == NULL) {
16611 if (errno != ENOENT)
16615 if (gethostname(myname, MAXHOSTNAMELEN) < 0)
16617 if ((mydomain = ckstrchr(myname, '.')) == NULL)
16621 while ((t = token())) switch(t) {
16632 * Allow match either for user's input host name
16633 * or official hostname. Also allow match of
16634 * incompletely-specified host in local domain.
16636 if (ckstrcmp(host, tokval,-1,1) == 0)
16638 if (ckstrcmp(ftp_host, tokval,-1,0) == 0)
16640 if ((tmp = ckstrchr(ftp_host, '.')) != NULL &&
16641 ckstrcmp(tmp, mydomain,-1,1) == 0 &&
16642 ckstrcmp(ftp_host, tokval, tmp-ftp_host,0) == 0 &&
16643 tokval[tmp - ftp_host] == '\0')
16645 if ((tmp = ckstrchr(host, '.')) != NULL &&
16646 ckstrcmp(tmp, mydomain,-1,1) == 0 &&
16647 ckstrcmp(host, tokval, tmp - host, 0) == 0 &&
16648 tokval[tmp - host] == '\0')
16654 while ((t = token()) && t != MACH && t != DEFAULT) switch(t) {
16659 *aname = malloc((unsigned) strlen(tokval) + 1);
16660 strcpy(*aname, tokval); /* safe */
16662 if (strcmp(*aname, tokval))
16667 if (strcmp(*aname, "anonymous") &&
16668 fstat(fileno(cfile), &stb) >= 0 &&
16669 (stb.st_mode & 077) != 0) {
16670 fprintf(stderr, "Error - .netrc file not correct mode.\n");
16671 fprintf(stderr, "Remove password or correct mode.\n");
16674 if (token() && *apass == 0) {
16675 *apass = malloc((unsigned) strlen(tokval) + 1);
16676 strcpy(*apass, tokval); /* safe */
16680 if (fstat(fileno(cfile), &stb) >= 0
16681 && (stb.st_mode & 077) != 0) {
16682 fprintf(stderr, "Error - .netrc file not correct mode.\n");
16683 fprintf(stderr, "Remove account or correct mode.\n");
16686 if (token() && *aacct == 0) {
16687 *aacct = malloc((unsigned) strlen(tokval) + 1);
16688 strcpy(*aacct, tokval); /* safe */
16693 fprintf(stderr, "Unknown .netrc keyword %s\n", tokval);
16707 #endif /* USE_RUSERPASS */
16709 static char *radixN =
16710 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
16712 static char pad = '=';
16715 radix_encode(inbuf, outbuf, inlen, outlen, decode)
16716 CHAR inbuf[], outbuf[];
16717 int inlen, *outlen, decode;
16724 for (i = 0, j = 0; inbuf[i] && inbuf[i] != pad; i++) {
16725 if ((p = ckstrchr(radixN, inbuf[i])) == NULL)
16733 outbuf[j++] |= D>>4;
16734 outbuf[j] = (D&15)<<4;
16737 outbuf[j++] |= D>>2;
16738 outbuf[j] = (D&3)<<6;
16748 case 2: if (D&15) return(3);
16749 if (strcmp((char *)&inbuf[i], "==")) return(2);
16751 case 3: if (D&3) return(3);
16752 if (strcmp((char *)&inbuf[i], "=")) return(2);
16756 for (i = 0, j = 0; i < inlen; i++) {
16759 outbuf[j++] = radixN[inbuf[i]>>2];
16760 c = (inbuf[i]&3)<<4;
16763 outbuf[j++] = radixN[c|inbuf[i]>>4];
16764 c = (inbuf[i]&15)<<2;
16767 outbuf[j++] = radixN[c|inbuf[i]>>6];
16768 outbuf[j++] = radixN[inbuf[i]&63];
16774 if (i%3) outbuf[j++] = radixN[c];
16776 case 1: outbuf[j++] = pad;
16777 case 2: outbuf[j++] = pad;
16779 outbuf[*outlen = j] = '\0';
16785 radix_error(e) int e;
16788 case 0: return("Success");
16789 case 1: return("Bad character in encoding");
16790 case 2: return("Encoding not properly padded");
16791 case 3: return("Decoded # of bits not a multiple of 8");
16792 case 4: return("Output buffer too small");
16793 default: return("Unknown error");
16796 /* END_RUSERPASS */
16799 /*---------------------------------------------------------------------------+
16801 | Package: srpftp |
16802 | Author: Eugene Jhong |
16804 +---------------------------------------------------------------------------*/
16807 * Copyright (c) 1997-1999 The Stanford SRP Authentication Project
16808 * All Rights Reserved.
16810 * Permission is hereby granted, free of charge, to any person obtaining
16811 * a copy of this software and associated documentation files (the
16812 * "Software"), to deal in the Software without restriction, including
16813 * without limitation the rights to use, copy, modify, merge, publish,
16814 * distribute, sublicense, and/or sell copies of the Software, and to
16815 * permit persons to whom the Software is furnished to do so, subject to
16816 * the following conditions:
16818 * The above copyright notice and this permission notice shall be
16819 * included in all copies or substantial portions of the Software.
16821 * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
16822 * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
16823 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
16825 * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
16826 * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
16827 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
16828 * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
16829 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16831 * In addition, the following conditions apply:
16833 * 1. Any software that incorporates the SRP authentication technology
16834 * must display the following acknowlegment:
16835 * "This product uses the 'Secure Remote Password' cryptographic
16836 * authentication system developed by Tom Wu (tjw@CS.Stanford.EDU)."
16838 * 2. Any software that incorporates all or part of the SRP distribution
16839 * itself must also display the following acknowledgment:
16840 * "This product includes software developed by Tom Wu and Eugene
16841 * Jhong for the SRP Distribution (http://srp.stanford.edu/srp/)."
16843 * 3. Redistributions in source or binary form must retain an intact copy
16844 * of this copyright notice and list of conditions.
16847 #define SRP_PROT_VERSION 1
16849 #ifdef CK_ENCRYPTION
16850 #define SRP_DEFAULT_CIPHER CIPHER_ID_CAST5_CBC
16852 #define SRP_DEFAULT_CIPHER CIPHER_ID_NONE
16853 #endif /* CK_ENCRYPTION */
16855 #define SRP_DEFAULT_HASH HASH_ID_SHA
16857 CHAR srp_pref_cipher = CIPHER_ID_DES3_ECB;
16858 CHAR srp_pref_hash = HASH_ID_SHA;
16860 static struct t_client *tc = NULL;
16861 static CHAR *skey = NULL;
16862 static krypto_context *incrypt = NULL;
16863 static krypto_context *outcrypt = NULL;
16865 typedef unsigned int srp_uint32;
16867 /*--------------------------------------------------------------+
16868 | srp_selcipher: select cipher |
16869 +--------------------------------------------------------------*/
16871 srp_selcipher (cname) char *cname; {
16874 if (!(cd = cipher_getdescbyname (cname))) {
16876 CHAR *list = cipher_getlist ();
16878 fprintf (stderr, "ftp: supported ciphers:\n\n");
16879 for (i = 0; i < strlen (list); i++)
16880 fprintf (stderr, " %s\n", (cipher_getdescbyid(list[i]))->name);
16881 fprintf (stderr, "\n");
16884 srp_pref_cipher = cd->id;
16888 /*--------------------------------------------------------------+
16889 | srp_selhash: select hash |
16890 +--------------------------------------------------------------*/
16892 srp_selhash (hname) char *hname; {
16895 if (!(hd = hash_getdescbyname (hname))) {
16897 CHAR *list = hash_getlist ();
16899 fprintf (stderr, "ftp: supported hash functions:\n\n");
16900 for (i = 0; i < strlen (list); i++)
16901 fprintf (stderr, " %s\n", (hash_getdescbyid(list[i]))->name);
16902 fprintf (stderr, "\n");
16905 srp_pref_hash = hd->id;
16909 /*--------------------------------------------------------------+
16910 | srp_userpass: get username and password |
16911 +--------------------------------------------------------------*/
16913 srp_userpass (host) char *host; {
16914 char tmp[BUFSIZ], prompt[PROMPTSIZ];
16918 #ifdef USE_RUSERPASS
16919 ruserpass (host, &user, &srp_pass, &srp_acct);
16920 #endif /* USE_RUSERPASS */
16922 while (user == NULL) {
16927 if (!myname) myname = "";
16929 ckmakxmsg(prompt,PROMPTSIZ," Name (",host,":",myname,"): ",
16930 NULL,NULL,NULL,NULL,NULL,NULL,NULL);
16932 ckmakmsg(prompt,PROMPTSIZ," Name (",host,"): ",NULL);
16934 ok = uq_txt(NULL,prompt,1,NULL,tmp,BUFSIZ,NULL,
16935 DEFAULT_UQ_TIMEOUT);
16936 if (!ok || *tmp == '\0')
16939 user = brstrip(tmp);
16941 ckstrncpy (srp_user, user,BUFSIZ);
16945 /*--------------------------------------------------------------+
16946 | srp_reset: reset srp information |
16947 +--------------------------------------------------------------*/
16950 if (tc) { t_clientclose (tc); tc = NULL; }
16951 if (incrypt) { krypto_delete (incrypt); incrypt = NULL; }
16952 if (outcrypt) { krypto_delete (outcrypt); outcrypt = NULL; }
16956 /*--------------------------------------------------------------+
16957 | srp_ftp_auth: perform srp authentication |
16958 +--------------------------------------------------------------*/
16960 srp_ftp_auth(host, user, pass)
16970 CHAR buf[FTP_BUFSIZ];
16971 CHAR tmp[FTP_BUFSIZ];
16973 int n, e, clen, blen, len, i;
16977 srp_pass = srp_acct = 0;
16979 n = ftpcmd("AUTH SRP",NULL,0,0,ftp_vbm);
16980 if (n != REPLY_CONTINUE) {
16982 fprintf(stderr, "SRP rejected as an authentication type\n");
16984 } else { /* Send protocol version */
16986 memset (vers, 0, 4);
16987 vers[3] = SRP_PROT_VERSION;
16989 printf ("SRP accepted as authentication type.\n");
16990 bp = tmp; blen = 0;
16991 srp_put (vers, &bp, 4, &blen);
16993 if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE))
16995 reply_parse = "ADAT=";
16996 n = ftpcmd("ADAT",buf,-1,-1,0);
16998 if (n == REPLY_CONTINUE) { /* Get protocol version */
17003 if (e = radix_encode(reply_parse, bp, 0, &blen, RADIX_DECODE))
17005 if (srp_get (&bp, &cp, &blen, &clen) != 4)
17008 if (host) { /* Get username/password if needed */
17009 srp_userpass (host);
17011 ckstrncpy (srp_user, user, BUFSIZ);
17014 bp = tmp; blen = 0; /* Send username */
17015 srp_put (srp_user, &bp, strlen (srp_user), &blen);
17017 if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE))
17019 reply_parse = "ADAT=";
17020 n = ftpcmd("ADAT",buf,-1,-1,0);
17022 if (n == REPLY_CONTINUE) { /* Get N, g and s */
17027 if (e = radix_encode (reply_parse, bp, 0, &blen, RADIX_DECODE))
17029 if (srp_get (&bp, &(N.data), &blen, &(N.len)) < 0)
17031 if (srp_get (&bp, &(g.data), &blen, &(g.len)) < 0)
17033 if (srp_get (&bp, &(s.data), &blen, &(s.len)) < 0)
17035 if ((tc = t_clientopen (srp_user, &N, &g, &s)) == NULL) {
17036 fprintf (stderr, "Unable to open SRP client structure.\n");
17039 wp = t_clientgenexp (tc); /* Send wp */
17040 bp = tmp; blen = 0;
17041 srp_put (wp->data, &bp, wp->len, &blen);
17043 if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE))
17045 reply_parse = "ADAT=";
17046 n = ftpcmd("ADAT",buf,-1,-1,0);
17048 if (n == REPLY_CONTINUE) { /* Get yp */
17053 if (e = radix_encode (reply_parse, bp, 0, &blen, RADIX_DECODE))
17055 if (srp_get (&bp, &(yp.data), &blen, &(yp.len)) < 0)
17058 static char ftppass[PASSBUFSIZ];
17061 ok = uq_txt(NULL," SRP Password: ",2,NULL,ftppass,PASSBUFSIZ,NULL,
17062 DEFAULT_UQ_TIMEOUT);
17064 srp_pass = brstrip(ftppass);
17066 t_clientpasswd (tc, srp_pass);
17067 memset (srp_pass, 0, strlen (srp_pass));
17068 skey = t_clientgetkey (tc, &yp); /* Send response */
17069 bp = tmp; blen = 0;
17070 srp_put (t_clientresponse (tc), &bp, 20, &blen);
17072 if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE))
17074 reply_parse = "ADAT=";
17075 n = ftpcmd("ADAT",buf,-1,-1,0);
17077 if (n == REPLY_CONTINUE) { /* Get response */
17082 if (e = radix_encode (reply_parse, bp, 0, &blen, RADIX_DECODE))
17084 if (srp_get (&bp, &cp, &blen, &clen) != 20)
17086 if (t_clientverify (tc, cp)) {
17087 fprintf (stderr, "WARNING: bad response to client challenge.\n");
17090 bp = tmp; blen = 0; /* Send nothing */
17091 srp_put ("\0", &bp, 1, &blen);
17093 if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE))
17095 reply_parse = "ADAT=";
17096 n = ftpcmd("ADAT",buf,-1,-1,0);
17098 if (n == REPLY_CONTINUE) { /* Get cipher & hash lists, seqnum */
17103 int clist_len, hlist_len;
17108 if (e = radix_encode (reply_parse, bp, 0, &blen, RADIX_DECODE))
17110 if (srp_get (&bp, &clist, &blen, &clist_len) < 0)
17112 if (srp_get (&bp, &hlist, &blen, &hlist_len) < 0)
17114 if (srp_get (&bp, &cp, &blen, &clen) != 4)
17116 memcpy (seqnum, cp, 4);
17117 if (cipher_supported (clist, srp_pref_cipher)) /* Choose cipher */
17118 cid = srp_pref_cipher;
17119 if (!cid && cipher_supported (clist, SRP_DEFAULT_CIPHER))
17120 cid = SRP_DEFAULT_CIPHER;
17122 CHAR *loclist = cipher_getlist ();
17123 for (i = 0; i < strlen (loclist); i++)
17124 if (cipher_supported (clist, loclist[i])) {
17130 fprintf (stderr, "Unable to agree on cipher.\n");
17135 if (srp_pref_hash && hash_supported (hlist, srp_pref_hash))
17136 hid = srp_pref_hash;
17138 if (!hid && hash_supported (hlist, SRP_DEFAULT_HASH))
17139 hid = SRP_DEFAULT_HASH;
17142 CHAR *loclist = hash_getlist ();
17143 for (i = 0; i < strlen (loclist); i++)
17144 if (hash_supported (hlist, loclist[i])) {
17150 fprintf (stderr, "Unable to agree on hash.\n");
17155 if (!(incrypt = krypto_new (cid, hid, skey, 20, NULL, 0, seqnum,
17159 /* Generate random number for outkey and outseqnum */
17161 t_random (seqnum, 4);
17163 /* Send cid, hid, outkey, outseqnum */
17165 bp = tmp; blen = 0;
17166 srp_put (&cid, &bp, 1, &blen);
17167 srp_put (&hid, &bp, 1, &blen);
17168 srp_put (seqnum, &bp, 4, &blen);
17170 if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE))
17172 reply_parse = "ADAT=";
17173 n = ftpcmd("ADAT",buf,-1,-1,0);
17177 if (!(outcrypt = krypto_new (cid, hid, skey+20, 20, NULL, 0, seqnum,
17181 t_clientclose (tc);
17184 if (n != REPLY_COMPLETE)
17190 printf ("SRP authentication succeeded.\n");
17191 printf ("Using cipher %s and hash function %s.\n",
17192 (cipher_getdescbyid(cid))->name,
17193 (hash_getdescbyid(hid))->name
17196 reply_parse = NULL;
17201 fprintf (stderr, "Base 64 encoding failed: %s.\n", radix_error (e));
17205 fprintf (stderr, "Base 64 decoding failed: %s.\n", radix_error (e));
17209 fprintf (stderr, "Unable to unmarshal authentication data.\n");
17213 fprintf (stderr, "SRP authentication failed, trying regular login.\n");
17214 reply_parse = NULL;
17218 /*--------------------------------------------------------------+
17219 | srp_put: put item to send buffer |
17220 +--------------------------------------------------------------*/
17222 srp_put (in, out, inlen, outlen)
17228 srp_uint32 net_len;
17230 net_len = htonl (inlen);
17231 memcpy (*out, &net_len, 4);
17233 *out += 4; *outlen += 4;
17235 memcpy (*out, in, inlen);
17237 *out += inlen; *outlen += inlen;
17241 /*--------------------------------------------------------------+
17242 | srp_get: get item from receive buffer |
17243 +--------------------------------------------------------------*/
17245 srp_get (in, out, inlen, outlen)
17251 srp_uint32 net_len;
17253 if (*inlen < 4) return -1;
17255 memcpy (&net_len, *in, 4); *inlen -= 4; *in += 4;
17256 *outlen = ntohl (net_len);
17258 if (*inlen < *outlen) return -1;
17260 *out = *in; *inlen -= *outlen; *in += *outlen;
17265 /*--------------------------------------------------------------+
17266 | srp_encode: encode control message |
17267 +--------------------------------------------------------------*/
17269 srp_encode (private, in, out, len)
17276 return krypto_msg_priv (outcrypt, in, out, len);
17278 return krypto_msg_safe (outcrypt, in, out, len);
17281 /*--------------------------------------------------------------+
17282 | srp_decode: decode control message |
17283 +--------------------------------------------------------------*/
17285 srp_decode (private, in, out, len)
17292 return krypto_msg_priv (incrypt, in, out, len);
17294 return krypto_msg_safe (incrypt, in, out, len);
17297 #endif /* FTP_SRP */
17303 The following code is from the Unix FTP client. Be sure to
17304 make sure that the functionality is not lost. Especially
17305 the Proxy stuff even though we have not yet implemented it.
17308 /* Send multiple files */
17311 ftp_mput(argc, argv) int argc; char **argv; {
17318 if (argc < 2 && !another(&argc, &argv, "local-files")) {
17319 printf("usage: %s local-files\n", argv[0]);
17325 oldintr = signal(SIGINT, mcancel);
17327 /* Replace with calls to cc_execute() */
17331 char *cp, *tp2, tmpbuf[CKMAXPATH];
17333 while ((cp = remglob(argv,0)) != NULL) {
17338 if (mflag && confirm(argv[0], cp)) {
17341 while (*tp && !islower(*tp)) {
17347 while ((*tp2 = *tp) != 0) {
17348 if (isupper(*tp2)) {
17349 *tp2 = 'a' + *tp2 - 'A';
17363 sendrequest((sunique) ? "STOU" : "STOR", cp, tp, 0, -1, -1, 0);
17364 if (!mflag && fromatty) {
17365 ointer = interactive;
17367 if (confirm("Continue with","mput")) {
17370 interactive = ointer;
17374 signal(SIGINT, oldintr);
17378 #endif /* FTP_PROXY */
17379 for (i = 1; i < argc; i++) {
17380 register char **cpp, **gargs;
17382 if (mflag && confirm(argv[0], argv[i])) {
17384 sendrequest((ftp_usn) ? "STOU" : "STOR", argv[i], tp, 0,-1,-1, 0);
17385 if (!mflag && fromatty) {
17386 ointer = interactive;
17388 if (confirm("Continue with","mput")) {
17391 interactive = ointer;
17396 gargs = ftpglob(argv[i]);
17397 if (globerr != NULL) {
17398 printf("%s\n", globerr);
17401 free((char *)gargs);
17405 for (cpp = gargs; cpp && *cpp != NULL; cpp++) {
17406 if (mflag && confirm(argv[0], *cpp)) {
17408 sendrequest((sunique) ? "STOU":"STOR", *cpp, tp, 0, -1, -1, 0);
17409 if (!mflag && fromatty) {
17410 ointer = interactive;
17412 if (confirm("Continue with","mput")) {
17415 interactive = ointer;
17419 if (gargs != NULL) {
17421 free((char *)gargs);
17424 signal(SIGINT, oldintr);
17428 /* Get multiple files */
17431 ftp_mget(argc, argv) int argc; char **argv; {
17435 char *cp, *tp, *tp2, tmpbuf[CKMAXPATH];
17438 if (argc < 2 && !another(&argc, &argv, "remote-files")) {
17439 printf("usage: %s remote-files\n", argv[0]);
17445 oldintr = signal(SIGINT,mcancel);
17446 /* Replace with calls to cc_execute() */
17448 while ((cp = remglob(argv,proxy)) != NULL) {
17453 if (mflag && confirm(argv[0], cp)) {
17456 while (*tp && !islower(*tp)) {
17462 while ((*tp2 = *tp) != 0) {
17463 if (isupper(*tp2)) {
17464 *tp2 = 'a' + *tp2 - 'A';
17472 rc = (recvrequest("RETR", tp, cp, "wb",
17473 tp != cp || !interactive) == 0,0,NULL,0,0,0);
17474 if (!mflag && fromatty) {
17475 ointer = interactive;
17477 if (confirm("Continue with","mget")) {
17480 interactive = ointer;
17484 signal(SIGINT,oldintr);
17489 /* Delete multiple files */
17492 mdelete(argc, argv) int argc; char **argv; {
17498 if (argc < 2 && !another(&argc, &argv, "remote-files")) {
17499 printf("usage: %s remote-files\n", argv[0]);
17505 oldintr = signal(SIGINT, mcancel);
17506 /* Replace with calls to cc_execute() */
17508 while ((cp = remglob(argv,0)) != NULL) {
17513 if (mflag && confirm(argv[0], cp)) {
17514 rc = (ftpcmd("DELE",cp,-1,-1,ftp_vbm) == REPLY_COMPLETE);
17515 if (!mflag && fromatty) {
17516 ointer = interactive;
17518 if (confirm("Continue with", "mdelete")) {
17521 interactive = ointer;
17525 signal(SIGINT, oldintr);
17530 /* Get a directory listing of multiple remote files */
17533 mls(argc, argv) int argc; char **argv; {
17536 char *cmd, mode[1], *dest;
17540 if (argc < 2 && !another(&argc, &argv, "remote-files"))
17542 if (argc < 3 && !another(&argc, &argv, "local-file")) {
17544 printf("usage: %s remote-files local-file\n", argv[0]);
17548 dest = argv[argc - 1];
17549 argv[argc - 1] = NULL;
17550 if (strcmp(dest, "-") && *dest != '|')
17551 if (!globulize(&dest) ||
17552 !confirm("output to local-file:", dest)) {
17556 cmd = argv[0][1] == 'l' ? "NLST" : "LIST";
17559 oldintr = signal(SIGINT, mcancel);
17560 /* Replace with calls to cc_execute() */
17562 for (i = 1; mflag && i < argc-1; ++i) {
17563 *mode = (i == 1) ? 'w' : 'a';
17564 rc = recvrequest(cmd, dest, argv[i], mode, 0,0,NULL,0,0,0);
17565 if (!mflag && fromatty) {
17566 ointer = interactive;
17568 if (confirm("Continue with", argv[0])) {
17571 interactive = ointer;
17574 signal(SIGINT, oldintr);
17580 remglob(argv,doswitch) char *argv[]; int doswitch; {
17582 static char buf[CKMAXPATH];
17583 static FILE *ftemp = NULL;
17584 static char **args;
17593 (void) fclose(ftemp);
17602 if ((cp = *++args) == NULL)
17606 if (ftemp == NULL) {
17607 (void) strcpy(temp, _PATH_TMP);
17610 (void) mktemp(temp);
17611 #endif /* MKSTEMP */
17612 #endif /* MKTEMP */
17614 oldhash = hash, hash = 0;
17619 #endif /* FTP_PROXY */
17620 for (mode = "wb"; *++argv != NULL; mode = "ab")
17621 recvrequest ("NLST", temp, *argv, mode, 0);
17626 #endif /* FTP_PROXY */
17628 ftemp = fopen(temp, "r");
17630 if (ftemp == NULL && (!dpyactive || ftp_deb)) {
17631 printf("Can't find list of remote files, oops\n");
17635 if (fgets(buf, CKMAXPATH, ftemp) == NULL) {
17636 fclose(ftemp), ftemp = NULL;
17639 if ((cp = ckstrchr(buf,'\n')) != NULL)
17643 #endif /* NOT_USED */
17644 #endif /* TCPSOCKET (top of file) */
17645 #endif /* SYSFTP (top of file) */
17646 #endif /* NOFTP (top of file) */