3 /* C K C F T P -- FTP Client for C-Kermit */
5 char *ckftpv = "FTP Client, 9.0.260, 14 Jul 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] */
188 #include <errno.h> /* Error number symbols */
190 #ifndef ERRNO_INCLUDED
191 #include <errno.h> /* Error number symbols */
192 #endif /* ERRNO_INCLUDED */
193 #endif /* HPUXPRE65 */
199 #define EPIPE 32 /* Broken pipe error */
202 /* Kermit includes */
208 #include "ckcnet.h" /* Includes ckctel.h */
209 #include "ckctel.h" /* (then why include it again?) */
213 #include "ckuath.h" /* SMS 2007/02/15 */
214 #endif /* def CK_SSL */
217 How to get the struct timeval definition so we can call select(). The
218 xxTIMEH symbols are defined in ckcdeb.h, overridden in various makefile
219 targets. The problem is: maybe we have already included some header file
220 that defined struct timeval, and maybe we didn't. If we did, we don't want
221 to include another header file that defines it again or the compilation will
222 fail. If we didn't, we have to include the header file where it's defined.
223 But in some cases even that won't work because of strict POSIX constraints
224 or somesuch, or because this introduces other conflicts (e.g. struct tm
225 multiply defined), in which case we have to define it ourselves, but this
226 can work only if we didn't already encounter a definition.
235 #endif /* SV68R3V6 */
236 #endif /* DCLTIMEVAL */
239 /* Also maybe in some places the elements must be unsigned... */
245 /* Currently we don't use this... */
251 #else /* !DCLTIMEVAL */
254 #include <sys/time.h>
255 #endif /* SYSTIMEH */
256 #endif /* NOSYSTIMEH */
259 #include <sys/timeb.h>
260 #endif /* SYSTIMEBH */
261 #endif /* NOSYSTIMEBH */
262 #endif /* DCLTIMEVAL */
264 /* 2010-03-09 SMS. VAX C needs help to find "sys". It's easier not to try. */
268 #include <sys/types.h>
269 #endif /* def VMS [else] */
274 #endif /* HAVE_STDLIB_H */
278 /* This section moved to ckcdeb.h */
292 #ifdef VMS /* SMS 2007/02/15 */
293 #include "ckvrtl.h" /* for utime() */
296 #include <sys/utime.h>
302 #endif /* SYSUTIMEH */
304 #endif /* NOSETTIME */
308 #include <sys/select.h>
309 #endif /* SELECT_H */
310 #endif /* SCO_OSR504 */
312 #ifndef INADDR_NONE /* 2010-03-29 */
313 #define INADDR_NONE -1
314 #endif /* INADDR_NONE */
316 /* select() dialects... */
319 #define BSDSELECT /* BSD select() syntax/semantics */
321 #define FD_SETSIZE 128
322 #endif /* FD_SETSIZE */
323 #ifdef HPUX6 /* For HP-UX 6.5 circa 1989 */
324 typedef long fd_mask;
325 #define NFDBITS (sizeof(fd_mask) * NBBY) /* bits per mask */
327 #define howmany(x, y) (((x)+((y)-1))/(y))
329 #define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
330 #define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
331 #define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
332 #define FD_COPY(f, t) bcopy(f, t, sizeof(*(f)))
333 #define FD_ZERO(p) bzero(p, sizeof(*(p)))
337 #ifdef OS2 /* OS/2 or Win32 */
347 #define BSDSELECT /* SMS 2007/02/15 */
350 /* Other select() peculiarities */
353 #ifndef HPUX10 /* HP-UX 9.xx and earlier */
355 /* The three interior args to select() are (int *) rather than (fd_set *) */
358 #endif /* INTSELECT */
359 #endif /* HPUX1100 */
363 #ifdef CK_SOCKS /* SOCKS Internet relay package */
364 #ifdef CK_SOCKS5 /* SOCKS 5 */
365 #define accept SOCKSaccept
366 #define bind SOCKSbind
367 #define connect SOCKSconnect
368 #define getsockname SOCKSgetsockname
369 #define listen SOCKSlisten
370 #else /* Not SOCKS 5 */
371 #define accept Raccept
373 #define connect Rconnect
374 #define getsockname Rgetsockname
375 #define listen Rlisten
376 #endif /* CK_SOCKS5 */
377 #endif /* CK_SOCKS */
380 extern char * tcp_http_proxy; /* Name[:port] of http proxy server */
381 extern int tcp_http_proxy_errno;
382 extern char * tcp_http_proxy_user;
383 extern char * tcp_http_proxy_pwd;
384 extern char * tcp_http_proxy_agent;
385 #define HTTPCPYL 1024
386 static char proxyhost[HTTPCPYL];
388 int ssl_ftp_proxy = 0; /* FTP over SSL/TLS Proxy Server */
390 /* Feature selection */
394 We don't use shutdown() because (a) we always call it just before close()
395 so it's redundant and unnecessary, and (b) it introduces a long pause on
396 some platforms like SV/68 R3.
398 /* #define USE_SHUTDOWN */
399 #endif /* USE_SHUTDOWN */
402 #ifndef NORESTART /* Restart / recover */
405 #endif /* FTP_RESTART */
406 #endif /* NORESTART */
407 #endif /* NORESEND */
409 #ifndef NOUPDATE /* Update mode */
412 #endif /* DOUPDATE */
413 #endif /* NOUPDATE */
415 #ifndef UNICODE /* Unicode required */
416 #ifndef NOCSETS /* for charset translation */
422 #ifndef HAVE_MSECS /* Millisecond timer */
428 #endif /* HAVE_MSECS */
431 #ifdef PIPESEND /* PUT from pipe */
435 #endif /* PIPESEND */
437 #ifndef NOSPL /* PUT from array */
440 #endif /* PUTARRAY */
452 There is a conflict between the Key Schedule formats used internally
453 within the standalone MIT KRB4 library and that used by Eric Young
454 in OpenSSL and his standalone DES library. Therefore, KRB4 FTP AUTH
455 cannot be supported when either of those two packages are used.
469 #ifndef NOFTP_GSSAPI /* 299 */
471 #endif /* NOFTP_GSSAPI */
474 #endif /* CK_KERBEROS */
476 /* FTP_SECURITY is defined if any of the above is selected */
491 #endif /* FTP_KRB4 */
492 #endif /* FTP_GSSAPI */
493 #endif /* FTP_SECURITY */
507 #endif /* CRYPT_DLL */
510 #define des_cblock Block
511 #define des_key_schedule Schedule
516 #include "kerberosIV/krb.h"
520 /* For some reason lost in history the Makefile Solaris targets have -Usun */
525 #define krb_get_err_text_entry krb_get_err_text
527 #endif /* FTP_KRB4 */
533 #endif /* HEADER_DES_H */
534 #endif /* FTP_KRB4 */
541 #endif /* HAVE_PWD_H */
543 #include "t_client.h"
548 #include <gssapi/gssapi.h>
550 Need to include the krb5 file, because we're doing manual fallback
551 from the v2 mech to the v1 mech. Once there's real negotiation,
552 we can be generic again.
554 #include <gssapi/gssapi_generic.h>
555 #include <gssapi/gssapi_krb5.h>
556 static gss_ctx_id_t gcontext;
559 /** exported constants defined in gssapi_krb5{,_nx}.h **/
561 /* these are bogus, but will compile */
564 * The OID of the draft krb5 mechanism, assigned by IETF, is:
565 * iso(1) org(3) dod(5) internet(1) security(5)
566 * kerberosv5(2) = 1.3.5.1.5.2
567 * The OID of the krb5_name type is:
568 * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
569 * krb5(2) krb5_name(1) = 1.2.840.113554.1.2.2.1
570 * The OID of the krb5_principal type is:
571 * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
572 * krb5(2) krb5_principal(2) = 1.2.840.113554.1.2.2.2
573 * The OID of the proposed standard krb5 mechanism is:
574 * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
575 * krb5(2) = 1.2.840.113554.1.2.2
576 * The OID of the proposed standard krb5 v2 mechanism is:
577 * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
578 * krb5v2(3) = 1.2.840.113554.1.2.3
583 * Encoding rules: The first two values are encoded in one byte as 40
584 * * value1 + value2. Subsequent values are encoded base 128, most
585 * significant digit first, with the high bit (\200) set on all octets
586 * except the last in each value's encoding.
589 static CONST gss_OID_desc
590 ck_krb5_gss_oid_array[] = {
591 /* this is the official, rfc-specified OID */
592 {9, "\052\206\110\206\367\022\001\002\002"},
593 /* this is the unofficial, wrong OID */
594 {5, "\053\005\001\005\002"},
595 /* this is the v2 assigned OID */
596 {9, "\052\206\110\206\367\022\001\002\003"},
597 /* these two are name type OID's */
598 {10, "\052\206\110\206\367\022\001\002\002\001"},
599 {10, "\052\206\110\206\367\022\001\002\002\002"},
604 CONST gss_OID_desc * CONST gss_mech_krb5_v2 = ck_krb5_gss_oid_array+2;
608 CONST gss_OID_desc * CONST gss_mech_krb5 = ck_krb5_gss_oid_array+0;
609 #endif /* MACOSX103 */
613 CONST gss_OID_desc * CONST gss_mech_krb5 = ck_krb5_gss_oid_array+0;
615 CONST gss_OID_desc * CONST gss_mech_krb5_old = ck_krb5_gss_oid_array+1;
617 CONST gss_OID_desc * CONST gss_nt_krb5_name = ck_krb5_gss_oid_array+3;
619 CONST gss_OID_desc * CONST gss_nt_krb5_principal = ck_krb5_gss_oid_array+4;
623 * See krb5/gssapi_krb5.c for a description of the algorithm for
624 * encoding an object identifier.
628 * The OID of user_name is:
629 * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
630 * generic(1) user_name(1) = 1.2.840.113554.1.2.1.1
632 * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
633 * generic(1) machine_uid_name(2) = 1.2.840.113554.1.2.1.2
635 * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
636 * generic(1) string_uid_name(3) = 1.2.840.113554.1.2.1.3
638 * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
639 * generic(1) service_name(4) = 1.2.840.113554.1.2.1.4
641 * 1(iso), 3(org), 6(dod), 1(internet), 5(security), 6(nametypes),
642 * 4(gss-api-exported-name)
643 * host_based_service_name (v2):
644 * iso (1) org (3), dod (6), internet (1), security (5), nametypes(6),
645 * gss-host-based-services(2)
648 static gss_OID_desc ck_oids[] = {
649 {10, "\052\206\110\206\367\022\001\002\001\001"},
650 {10, "\052\206\110\206\367\022\001\002\001\002"},
651 {10, "\052\206\110\206\367\022\001\002\001\003"},
652 {10, "\052\206\110\206\367\022\001\002\001\004"},
653 { 6, "\053\006\001\005\006\004"},
654 { 6, "\053\006\001\005\006\002"},
657 static gss_OID ck_gss_nt_user_name = ck_oids+0;
658 static gss_OID ck_gss_nt_machine_uid_name = ck_oids+1;
659 static gss_OID ck_gss_nt_string_uid_name = ck_oids+2;
660 static gss_OID ck_gss_nt_service_name = ck_oids+3;
661 static gss_OID ck_gss_nt_exported_name = ck_oids+4;
662 static gss_OID ck_gss_nt_service_name_v2 = ck_oids+5;
664 #endif /* FTP_GSSAPI */
677 #endif /* CK_ENCRYPTION */
678 #endif /* FTP_KRB4 */
682 #endif /* FTP_GSSAPI */
685 extern int k95stdout, wherex[], wherey[];
686 extern unsigned char colorcmd;
690 static char ftp_realm[REALM_SZ + 1];
691 static KTEXT_ST ftp_tkt;
693 static LEASH_CREDENTIALS ftp_cred;
695 static CREDENTIALS ftp_cred;
697 static MSG_DAT ftp_msg_data;
698 static des_key_schedule ftp_sched;
699 static int foo[4] = {99,99,99,99};
700 #endif /* FTP_KRB4 */
702 /* getreply() function codes */
704 #define GRF_AUTH 1 /* Reply to AUTH command */
705 #define GRF_FEAT 2 /* Reply to FEAT command */
707 /* Operational definitions */
709 #define DEF_VBM 0 /* Default verbose mode */
710 /* #define SETVBM */ /* (see getreply) */
712 #define URL_ONEFILE /* GET, not MGET, for FTP URL */
714 #define FTP_BUFSIZ 10240 /* Max size for FTP cmds & replies */
715 #define SRVNAMLEN 32 /* Max length for server type name */
717 #define PASSBUFSIZ 256
718 #define PROMPTSIZ 256
720 #ifndef MGETMAX /* Max operands for MGET command */
725 #define FUDGE_FACTOR 100
729 Amount of growth from cleartext to ciphertext. krb_mk_priv adds this
730 number bytes. Must be defined for each auth type.
731 GSSAPI appears to add 52 bytes, but I'm not sure it is a constant--hartmans
732 3DES requires 56 bytes. Lets use 96 just to be sure.
736 #define FUDGE_FACTOR 96
737 #endif /* FUDGE_FACTOR */
738 #endif /* FTP_GSSAPI */
742 #define FUDGE_FACTOR 32
743 #endif /* FUDGE_FACTOR */
744 #endif /* FTP_KRB4 */
746 #ifndef FUDGE_FACTOR /* In case no auth types define it */
747 #define FUDGE_FACTOR 0
748 #endif /* FUDGE_FACTOR */
750 #ifndef MAXHOSTNAMELEN
751 #define MAXHOSTNAMELEN 64
752 #endif /* MAXHOSTNAMELEN */
753 #define MAX_DNS_NAMELEN (15*(MAXHOSTNAMELEN + 1)+1)
755 /* Fascist compiler toadying */
758 #ifdef COMMENT /* Might be needed here and there */
759 #define SENDARG2TYPE const char *
761 #define SENDARG2TYPE char *
763 #endif /* SENDARG2TYPE */
765 /* Common text messages */
767 static char *nocx = "?No FTP control connection\n";
769 static char *fncnam[] = {
770 "rename", "overwrite", "backup", "append", "discard", "ask", "update",
774 /* Macro definitions */
776 /* Used to speed up text-mode PUTs */
777 #define zzout(fd,c) \
778 ((fd<0)?(-1):((nout>=ucbufsiz)?(zzsend(fd,c)):(ucbuf[nout++]=c)))
780 #define CHECKCONN() if(!connected){printf(nocx);return(-9);}
785 extern struct urldata g_url;
789 extern char *zinbuffer, *zoutbuffer; /* Regular Kermit file i/o */
791 extern char zinbuffer[], zoutbuffer[];
793 extern char *zinptr, *zoutptr;
794 extern int zincnt, zoutcnt, zobufsize, fncact;
797 extern int f_tmpdir; /* Directory changed temporarily */
798 extern char savdir[]; /* For saving current directory */
800 #endif /* CK_TMPDIR */
802 extern char * rfspec, * sfspec, * srfspec, * rrfspec; /* For WHERE command */
804 extern xx_strp xxstring;
805 extern struct keytab onoff[], txtbin[], rpathtab[];
806 extern int nrpathtab, xfiletype, patterns, gnferror, moving, what, pktnum;
807 extern int success, nfils, sndsrc, quiet, nopush, recursive, inserver, binary;
808 extern int filepeek, nscanfile, fsecs, xferstat, xfermode, lastxfer, tsecs;
809 extern int backgrd, spackets, rpackets, spktl, rpktl, xaskmore, cmd_rows;
810 extern int nolinks, msgflg, keep;
811 extern CK_OFF_T fsize, ffc, tfc, sendstart, sndsmaller, sndlarger, rs_len;
812 extern long filcnt, xfsecs, tfcps, cps, oldcps;
815 int ftp_timed_out = 0;
816 long ftp_timeout = 0;
817 #endif /* FTP_TIMEOUT */
820 extern CKFLOAT fptsecs, fpfsecs, fpxfsecs;
825 extern char filnam[], * filefile, myhost[];
826 extern char * snd_move, * rcv_move, * snd_rename, * rcv_rename;
827 extern int g_skipbup, skipbup, sendmode;
828 extern int g_displa, fdispla, displa;
831 extern int locus, autolocus;
835 extern int nfilc, dcset7, dcset8, fileorder;
836 extern struct csinfo fcsinfo[];
837 extern struct keytab fcstab[];
841 extern char sndbefore[], sndafter[], *sndexcept[]; /* Selection criteria */
842 extern char sndnbefore[], sndnafter[], *rcvexcept[];
845 extern char * remdest;
846 extern int remfile, remappd, rempipe;
849 extern int cmd_quoting;
851 extern int sndxlo, sndxhi, sndxin;
852 extern char sndxnam[];
853 extern char **a_ptr[]; /* Array pointers */
854 extern int a_dim[]; /* Array dimensions */
855 #endif /* PUTARRAY */
858 #ifndef NOMSEND /* MPUT and ADD SEND-LIST lists */
859 extern char *msfiles[];
860 extern int filesinlist;
861 extern struct filelist * filehead;
862 extern struct filelist * filetail;
863 extern struct filelist * filenext;
865 extern char fspec[]; /* Most recent filespec */
866 extern int fspeclen; /* Length of fspec[] buffer */
871 extern char * sndfilter, * rcvfilter;
872 #endif /* PIPESEND */
875 extern int ckrooterr;
879 extern int krb4_autoget;
880 _PROTOTYP(char * ck_krb4_realmofhost,(char *));
884 extern int krb5_autoget;
885 extern int krb5_d_no_addresses;
886 _PROTOTYP(char * ck_krb5_realmofhost,(char *));
890 extern char *atmbuf; /* Atom buffer (malloc'd) */
891 extern char *cmdbuf; /* Command buffer (malloc'd) */
892 extern char *line; /* Big string buffer #1 */
893 extern char *tmpbuf; /* Big string buffer #2 */
895 extern char atmbuf[]; /* The same, but static */
896 extern char cmdbuf[];
898 extern char tmpbuf[];
901 extern char * cmarg, * cmarg2, ** cmlist; /* For setting up file lists */
903 /* Public variables declared here */
906 int ftpget = 1; /* GET/PUT/REMOTE orientation FTP */
908 int ftpget = 2; /* GET/PUT/REMOTE orientation AUTO */
910 int ftpcode = -1; /* Last FTP response code */
911 int ftp_cmdlin = 0; /* FTP invoked from command line */
912 int ftp_fai = 0; /* FTP failure count */
913 int ftp_deb = 0; /* FTP debugging */
914 int ftp_dis = -1; /* FTP display style */
915 int ftp_log = 1; /* FTP Auto-login */
917 int ftp_action = 0; /* FTP action from command line */
918 int ftp_dates = 1; /* Set file dates from server */
919 int ftp_xfermode = XMODE_A; /* FTP-specific transfer mode */
921 char ftp_reply_str[FTP_BUFSIZ] = ""; /* Last line of previous reply */
922 char ftp_srvtyp[SRVNAMLEN] = { NUL, NUL }; /* Server's system type */
923 char ftp_user_host[MAX_DNS_NAMELEN]= ""; /* FTP hostname specified by user */
924 char * ftp_host = NULL; /* FTP hostname */
925 char * ftp_logname = NULL; /* FTP username */
926 char * ftp_rdir = NULL; /* Remote directory from cmdline */
927 char * ftp_apw = NULL; /* Anonymous password */
929 /* Definitions and typedefs needed for prototypes */
931 #define sig_t my_sig_t
932 #define sigtype SIGTYP
933 typedef sigtype (*sig_t)();
935 /* Static global variables */
937 static char ftpsndbuf[FTP_BUFSIZ+64];
939 static char * fts_sto = NULL;
941 static int ftpsndret = 0;
942 static struct _ftpsnd {
943 sig_t oldintr, oldintp;
947 char * cmd, * local, * remote;
955 This is just a first stab -- these strings should match how the
956 corresponding FTP servers identify themselves.
959 static char * myostype = "UNIX";
963 static char * myostype = "VMS";
967 static char * myostype = "WIN32";
969 static char * myostype = "OS/2";
972 static char * myostype = "UNSUPPORTED";
977 static int noinit = 0; /* Don't send REST, STRU, MODE */
978 static int alike = 0; /* Client/server like platforms */
979 static int local = 1; /* Shadows Kermit global 'local' */
980 static int dout = -1; /* Data connection file descriptor */
981 static int dpyactive = 0; /* Data transfer is active */
982 static int globaldin = -1; /* Data connection f.d. */
983 static int out2screen = 0; /* GET output is to screen */
984 static int forcetype = 0; /* Force text or binary mode */
985 static int cancelfile = 0; /* File canceled */
986 static int cancelgroup = 0; /* Group canceled */
987 static int anonymous = 0; /* Logging in as anonymous */
988 static int loggedin = 0; /* Logged in (or not) */
989 static int puterror = 0; /* What to do on PUT error */
990 static int geterror = 0; /* What to do on GET error */
991 static int rfrc = 0; /* remote_files() return code */
992 static int okrestart = 0; /* Server understands REST */
993 static int printlines = 0; /* getreply()should print data lines */
994 static int haveurl = 0; /* Invoked by command-line FTP URL */
995 static int mdtmok = 1; /* Server supports MDTM */
996 static int sizeok = 1;
997 static int featok = 1;
998 static int mlstok = 1;
999 static int stouarg = 1;
1000 static int typesent = 0;
1001 static int havesigint = 0;
1002 static long havetype = 0;
1003 static CK_OFF_T havesize = (CK_OFF_T)-1;
1004 static char * havemdtm = NULL;
1005 static int mgetmethod = 0; /* NLST or MLSD */
1006 static int mgetforced = 0;
1008 static int i, /* j, k, */ x, y, z; /* Volatile temporaries */
1009 static int c0, c1; /* Temp variables for characters */
1011 static char putpath[CKMAXPATH+1] = { NUL, NUL };
1012 static char asnambuf[CKMAXPATH+1] = { NUL, NUL };
1014 #define RFNBUFSIZ 4096 /* Remote filename buffer size */
1016 static unsigned int maxbuf = 0, actualbuf = 0;
1017 static CHAR *ucbuf = NULL;
1018 static int ucbufsiz = 0;
1019 static unsigned int nout = 0; /* Number of chars in ucbuf */
1021 static jmp_buf recvcancel;
1022 static jmp_buf sendcancel;
1023 static jmp_buf ptcancel;
1024 static jmp_buf jcancel;
1025 static int ptabflg = 0;
1027 /* Protection level symbols */
1029 #define FPL_CLR 1 /* Clear */
1030 #define FPL_SAF 2 /* Safe */
1031 #define FPL_PRV 3 /* Private */
1032 #define FPL_CON 4 /* Confidential */
1034 /* Symbols for file types returned by MLST/MLSD */
1036 #define FTYP_FILE 1 /* Regular file */
1037 #define FTYP_DIR 2 /* Directory */
1038 #define FTYP_CDIR 3 /* Current directory */
1039 #define FTYP_PDIR 4 /* Parent directory */
1041 /* File type symbols keyed to the file-type symbols from ckcker.h */
1043 #define FTT_ASC XYFT_T /* ASCII (text) */
1044 #define FTT_BIN XYFT_B /* Binary (image) */
1045 #define FTT_TEN XYFT_X /* TENEX (TOPS-20) */
1047 /* Server feature table - sfttab[0] > 0 means server supports FEAT and OPTS */
1049 static int sfttab[16] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
1051 #define SFT_AUTH 1 /* FTP server feature codes */
1062 #define CNV_AUTO 2 /* FTP filename conversion */
1066 /* SET FTP values */
1068 static int /* SET FTP values... */
1069 ftp_aut = 1, /* Auto-authentication */
1071 ftp_cry = 1, /* Auto-encryption */
1072 ftp_cfw = 0, /* Credential forwarding */
1073 #endif /* FTP_SECURITY */
1074 ftp_cpl = FPL_CLR, /* Command protection level */
1075 ftp_dpl = FPL_CLR, /* Data protection level */
1077 ftp_prx = 0, /* Use proxy */
1078 #endif /* FTP_PROXY */
1079 sav_psv = -1, /* For saving passive mode */
1080 ftp_psv = 1, /* Passive mode */
1081 ftp_spc = 1, /* Send port commands */
1082 ftp_typ = FTT_ASC, /* Type */
1083 get_auto = 1, /* Automatic type switching for GET */
1084 tenex = 0, /* Type is Tenex */
1085 ftp_usn = 0, /* Unique server names */
1086 ftp_prm = 0, /* Permissions */
1087 ftp_cnv = CNV_AUTO, /* Filename conversion (2 = auto) */
1088 ftp_vbm = DEF_VBM, /* Verbose mode */
1089 ftp_vbx = DEF_VBM, /* Sticky version of same */
1090 ftp_err = 0, /* Error action */
1091 ftp_fnc = -1; /* Filename collision action */
1094 static int ftp_bug_use_ssl_v2 = 0; /* use SSLv2 for AUTH SSL */
1099 ftp_csr = -1, /* Remote (server) character set */
1102 #endif /* NOCSETS */
1103 ftp_xla = 0; /* Character-set translation on/off */
1105 ftp_csx = -1, /* Remote charset currently in use */
1106 ftp_csl = -1; /* Local charset currently in use */
1108 static int g_ftp_typ = FTT_ASC; /* For saving and restoring ftp_typ */
1110 char * ftp_nml = NULL; /* /NAMELIST */
1111 char * ftp_tmp = NULL; /* Temporary string */
1112 static char * ftp_acc = NULL; /* Account string */
1113 static char * auth_type = NULL; /* Authentication type */
1114 static char * srv_renam = NULL; /* Server-rename string */
1115 FILE * fp_nml = NULL; /* Namelist file pointer */
1117 static int csocket = -1; /* Control socket */
1118 static int connected = 0; /* Connected to FTP server */
1119 /* static unsigned short ftp_port = 0; */ /* FTP port */
1120 /* static int ftp_port = 0; */ /* SMS 2007/02/15 */
1121 static int ftp_port = 0; /* fdc 2007/08/30 */
1123 static int hostcmd = 0; /* Has HOST command been sent */
1124 #endif /* FTPHOST */
1125 static int form, mode, stru, bytesize, curtype = FTT_ASC;
1126 static char bytename[8];
1128 /* For parsing replies to FTP server command */
1129 static char *reply_parse, reply_buf[FTP_BUFSIZ], *reply_ptr;
1132 static int proxy, unix_proxy
1133 #endif /* FTP_PROXY */
1135 static char pasv[64]; /* Passive-mode port */
1136 static int passivemode = 0;
1137 static int sendport = 0;
1138 static int servertype = 0; /* FTP server's OS type */
1140 static int testing = 0;
1141 static char ftpcmdbuf[FTP_BUFSIZ];
1143 /* Macro definitions */
1145 #define UC(b) ckitoa(((int)b)&0xff)
1146 #define nz(x) ((x) == 0 ? 1 : (x))
1148 /* Command tables and definitions */
1150 #define FTP_ACC 1 /* FTP command keyword codes */
1190 struct keytab gprtab[] = { /* GET-PUT-REMOTE keywords */
1196 static struct keytab qorp[] = { /* QUIT or PROCEED keywords */
1197 { "proceed", 0, 0 }, /* 0 = proceed */
1198 { "quit", 1, 0 } /* 1 = quit */
1201 static struct keytab ftpcmdtab[] = { /* FTP command table */
1202 { "account", FTP_ACC, 0 },
1203 { "append", FTP_APP, 0 },
1204 { "bye", FTP_CLS, 0 },
1205 { "cd", FTP_CWD, 0 },
1206 { "cdup", FTP_GUP, 0 },
1207 { "check", FTP_CHK, 0 },
1208 { "chmod", FTP_CHM, 0 },
1209 { "close", FTP_CLS, 0 },
1210 { "cwd", FTP_CWD, CM_INV },
1211 { "delete", FTP_MDE, 0 },
1212 { "directory", FTP_DIR, 0 },
1213 { "disable", FTP_DIS, 0 },
1214 { "enable", FTP_ENA, 0 },
1215 { "features", FTP_FEA, 0 },
1216 { "get", FTP_GET, 0 },
1217 { "help", FTP_HLP, 0 },
1218 { "idle", FTP_IDL, 0 },
1219 { "login", FTP_USR, CM_INV },
1220 { "mdelete", FTP_MDE, CM_INV },
1221 { "mget", FTP_MGE, 0 },
1222 { "mkdir", FTP_MKD, 0 },
1223 { "modtime", FTP_MOD, 0 },
1224 { "mput", FTP_MPU, 0 },
1225 { "open", FTP_OPN, 0 },
1226 { "opt", FTP_OPT, CM_INV|CM_ABR },
1227 { "opts", FTP_OPT, CM_INV },
1228 { "options", FTP_OPT, 0 },
1229 { "put", FTP_PUT, 0 },
1230 { "pwd", FTP_PWD, 0 },
1231 { "quit", FTP_CLS, CM_INV },
1232 { "quote", FTP_QUO, 0 },
1233 { "reget", FTP_RGE, 0 },
1234 { "rename", FTP_REN, 0 },
1235 { "reput", FTP_REP, 0 },
1236 { "resend", FTP_REP, CM_INV },
1237 { "reset", FTP_RES, 0 },
1238 { "rmdir", FTP_RMD, 0 },
1239 { "send", FTP_PUT, CM_INV },
1240 { "site", FTP_SIT, 0 },
1241 { "size", FTP_SIZ, 0 },
1242 { "status", FTP_STA, 0 },
1243 { "system", FTP_SYS, 0 },
1244 { "type", FTP_TYP, 0 },
1245 { "umask", FTP_UMA, 0 },
1246 { "up", FTP_GUP, CM_INV },
1247 { "user", FTP_USR, 0 },
1248 { "vdirectory",FTP_VDI, 0 },
1251 static int nftpcmd = (sizeof(ftpcmdtab) / sizeof(struct keytab)) - 1;
1253 #define OPN_ANO 1 /* FTP OPEN switch codes */
1266 static struct keytab tlstab[] = { /* FTP SSL/TLS switches */
1267 { "/ssl", OPN_TLS, 0 },
1268 { "/tls", OPN_TLS, 0 },
1271 static int ntlstab = (sizeof(tlstab) / sizeof(struct keytab)) - 1;
1273 #endif /* FTP_SECURITY */
1275 static struct keytab ftpswitab[] = { /* FTP command switches */
1276 { "/account", OPN_ACC, CM_ARG },
1277 { "/active", OPN_ACT, 0 },
1278 { "/anonymous", OPN_ANO, 0 },
1279 { "/noinit", OPN_NIN, 0 },
1280 { "/nologin", OPN_NOL, 0 },
1281 { "/passive", OPN_PSV, 0 },
1282 { "/password", OPN_PSW, CM_ARG },
1283 { "/user", OPN_USR, CM_ARG },
1286 static int nftpswi = (sizeof(ftpswitab) / sizeof(struct keytab)) - 1;
1288 /* FTP { ENABLE, DISABLE } items */
1296 static struct keytab ftpenatab[] = {
1297 { "AUTH", ENA_AUTH, 0 },
1298 { "FEAT", ENA_FEAT, 0 },
1299 { "MDTM", ENA_MDTM, 0 },
1300 { "ML", ENA_MLST, CM_INV|CM_ABR },
1301 { "MLS", ENA_MLST, CM_INV|CM_ABR },
1302 { "MLSD", ENA_MLST, CM_INV },
1303 { "MLST", ENA_MLST, 0 },
1304 { "SIZE", ENA_SIZE, 0 },
1307 static int nftpena = (sizeof(ftpenatab) / sizeof(struct keytab)) - 1;
1309 /* SET FTP command keyword indices */
1311 #define FTS_AUT 1 /* Autoauthentication */
1312 #define FTS_CRY 2 /* Encryption */
1313 #define FTS_LOG 3 /* Autologin */
1314 #define FTS_CPL 4 /* Command protection level */
1315 #define FTS_CFW 5 /* Credentials forwarding */
1316 #define FTS_DPL 6 /* Data protection level */
1317 #define FTS_DBG 7 /* Debugging */
1318 #define FTS_PSV 8 /* Passive mode */
1319 #define FTS_SPC 9 /* Send port commands */
1320 #define FTS_TYP 10 /* (file) Type */
1321 #define FTS_USN 11 /* Unique server names (for files) */
1322 #define FTS_VBM 12 /* Verbose mode */
1323 #define FTS_ATP 13 /* Authentication type */
1324 #define FTS_CNV 14 /* Filename conversion */
1325 #define FTS_TST 15 /* Test (progress) messages */
1326 #define FTS_PRM 16 /* (file) Permissions */
1327 #define FTS_XLA 17 /* Charset translation */
1328 #define FTS_CSR 18 /* Server charset */
1329 #define FTS_ERR 19 /* Error action */
1330 #define FTS_FNC 20 /* Collision */
1331 #define FTS_SRP 21 /* SRP options */
1332 #define FTS_GFT 22 /* GET automatic file-type switching */
1333 #define FTS_DAT 23 /* Set file dates */
1334 #define FTS_STO 24 /* Server time offset */
1335 #define FTS_APW 25 /* Anonymous password */
1336 #define FTS_DIS 26 /* File-transfer display style */
1337 #define FTS_BUG 27 /* Bug(s) */
1338 #define FTS_TMO 28 /* Timeout */
1342 #define FTB_SV2 1 /* use SSLv2 */
1344 static struct keytab ftpbugtab[] = {
1345 { "use-ssl-v2", FTB_SV2, 0 }
1347 static int nftpbug = (sizeof(ftpbugtab) / sizeof(struct keytab));
1349 /* FTP PUT options (mutually exclusive, not a bitmask) */
1351 #define PUT_UPD 1 /* Update */
1352 #define PUT_RES 2 /* Restart */
1353 #define PUT_SIM 4 /* Simulation */
1354 #define PUT_DIF 8 /* Dates Differ */
1356 static struct keytab ftpcolxtab[] = { /* SET FTP COLLISION options */
1358 { "append", XYFX_A, 0 }, /* append to old file */
1361 { "ask", XYFX_Q, 0 }, /* ask what to do (not implemented) */
1363 { "backup", XYFX_B, 0 }, /* rename old file */
1365 { "dates-differ", XYFX_M, 0 }, /* accept if dates differ */
1366 { "discard", XYFX_D, 0 }, /* don't accept new file */
1367 { "no-supersede", XYFX_D, CM_INV }, /* ditto (MSK compatibility) */
1369 { "overwrite", XYFX_X, 0 }, /* overwrite the old file */
1370 { "rename", XYFX_R, 0 }, /* rename the incoming file */
1371 #ifndef MAC /* This crashes Mac Kermit. */
1372 { "update", XYFX_U, 0 }, /* replace if newer */
1376 static int nftpcolx = (sizeof(ftpcolxtab) / sizeof(struct keytab)) - 1;
1380 /* FTP authentication options */
1382 #define FTA_AUTO 0 /* Auto */
1383 #define FTA_SRP 1 /* SRP */
1384 #define FTA_GK5 2 /* Kerberos 5 */
1385 #define FTA_K4 3 /* Kerberos 4 */
1386 #define FTA_SSL 4 /* SSL */
1387 #define FTA_TLS 5 /* TLS */
1389 /* FTP authentication types */
1392 static int ftp_auth_type[FTPATYPS] = {
1394 FTA_GK5, /* GSSAPI Kerberos 5 */
1395 #endif /* FTP_GK5 */
1398 #endif /* FTP_SRP */
1400 FTA_K4, /* Kerberos 4 */
1401 #endif /* FTP_KRB4 */
1409 static struct keytab ftpauth[] = { /* SET FTP AUTHTYPE cmd table */
1410 { "automatic", FTA_AUTO, CM_INV },
1412 { "gssapi-krb5", FTA_GK5, 0 },
1413 #endif /* FTP_GSSAPI */
1415 { "k4", FTA_K4, CM_INV },
1416 #endif /* FTP_KRB4 */
1418 { "k5", FTA_GK5, CM_INV },
1419 #endif /* FTP_GSSAPI */
1421 { "kerberos4", FTA_K4, 0 },
1422 #endif /* FTP_KRB4 */
1424 { "kerberos5", FTA_GK5, CM_INV },
1425 #endif /* FTP_GSSAPI */
1427 { "kerberos_iv",FTA_K4, CM_INV },
1428 #endif /* FTP_KRB4 */
1430 { "kerberos_v", FTA_GK5, CM_INV },
1431 #endif /* FTP_GSSAPI */
1433 { "krb4", FTA_K4, CM_INV },
1434 #endif /* FTP_KRB4 */
1436 { "krb5", FTA_GK5, CM_INV },
1437 #endif /* FTP_GSSAPI */
1439 { "srp", FTA_SRP, 0 },
1440 #endif /* FTP_SRP */
1442 { "ssl", FTA_SSL, 0 },
1443 { "tls", FTA_TLS, 0 },
1447 static int nftpauth = (sizeof(ftpauth) / sizeof(struct keytab)) - 1;
1450 #define SRP_CIPHER 1
1452 static struct keytab ftpsrp[] = { /* SET FTP SRP command table */
1453 { "cipher", SRP_CIPHER, 0 },
1454 { "hash", SRP_HASH, 0 },
1457 static int nftpsrp = (sizeof(ftpsrp) / sizeof(struct keytab)) - 1;
1458 #endif /* FTP_SRP */
1459 #endif /* FTP_SECURITY */
1461 static struct keytab ftpset[] = { /* SET FTP commmand table */
1462 { "anonymous-password", FTS_APW, 0 },
1464 { "authtype", FTS_ATP, 0 },
1465 { "autoauthentication", FTS_AUT, 0 },
1466 { "autoencryption", FTS_CRY, 0 },
1467 #endif /* FTP_SECURITY */
1468 { "autologin", FTS_LOG, 0 },
1469 { "bug", FTS_BUG, 0 },
1471 { "character-set-translation",FTS_XLA, 0 },
1472 #endif /* NOCSETS */
1473 { "collision", FTS_FNC, 0 },
1475 { "command-protection-level", FTS_CPL, 0 },
1476 { "cpl", FTS_CPL, CM_INV },
1477 { "credential-forwarding", FTS_CFW, 0 },
1478 { "da", FTS_DAT, CM_INV|CM_ABR },
1479 { "data-protection-level", FTS_DPL, 0 },
1480 #endif /* FTP_SECURITY */
1481 { "dates", FTS_DAT, 0 },
1482 { "debug", FTS_DBG, 0 },
1483 { "display", FTS_DIS, 0 },
1485 { "dpl", FTS_DPL, CM_INV },
1486 #endif /* FTP_SECURITY */
1487 { "error-action", FTS_ERR, 0 },
1488 { "filenames", FTS_CNV, 0 },
1489 { "get-filetype-switching", FTS_GFT, 0 },
1490 { "passive-mode", FTS_PSV, 0 },
1491 { "pasv", FTS_PSV, CM_INV },
1492 { "permissions", FTS_PRM, 0 },
1493 { "progress-messages", FTS_TST, 0 },
1494 { "send-port-commands", FTS_SPC, 0 },
1496 { "server-character-set", FTS_CSR, 0 },
1497 #endif /* NOCSETS */
1498 { "server-time-offset", FTS_STO, 0 },
1500 { "srp", FTS_SRP, 0 },
1502 { "srp", FTS_SRP, CM_INV },
1503 #endif /* FTP_SRP */
1505 { "timeout", FTS_TMO, 0 },
1506 #endif /* FTP_TIMEOUT */
1507 { "type", FTS_TYP, 0 },
1508 { "unique-server-names", FTS_USN, 0 },
1509 { "verbose-mode", FTS_VBM, 0 },
1512 static int nftpset = (sizeof(ftpset) / sizeof(struct keytab)) - 1;
1515 GET and PUT switches are approximately the same as Kermit GET and SEND,
1516 and use the same SND_xxx definitions, but hijack a couple for FTP use.
1517 Don't just make up new ones, since the number of SND_xxx options must be
1518 known in advance for the switch-parsing arrays.
1520 #define SND_USN SND_PRO /* /UNIQUE instead of /PROTOCOL */
1521 #define SND_PRM SND_PIP /* /PERMISSIONS instead of /PIPES */
1522 #define SND_TEN SND_CAL /* /TENEX instead of /CALIBRATE */
1524 static struct keytab putswi[] = { /* FTP PUT switch table */
1525 { "/after", SND_AFT, CM_ARG },
1527 { "/array", SND_ARR, CM_ARG },
1528 #endif /* PUTARRAY */
1529 { "/as", SND_ASN, CM_ARG|CM_INV|CM_ABR },
1530 { "/as-name", SND_ASN, CM_ARG },
1531 { "/ascii", SND_TXT, CM_INV },
1532 { "/b", SND_BIN, CM_INV|CM_ABR },
1533 { "/before", SND_BEF, CM_ARG },
1534 { "/binary", SND_BIN, 0 },
1536 { "/command", SND_CMD, CM_PSH },
1537 #endif /* PUTPIPE */
1539 /* This works but it's dangerous */
1541 { "/dates-differ", SND_DIF, CM_INV },
1542 #endif /* DOUPDATE */
1543 #endif /* COMMENT */
1544 { "/delete", SND_DEL, 0 },
1546 { "/dotfiles", SND_DOT, 0 },
1547 #endif /* UNIXOROSK */
1548 { "/error-action", SND_ERR, CM_ARG },
1549 { "/except", SND_EXC, CM_ARG },
1550 { "/filenames", SND_NAM, CM_ARG },
1553 { "/filter", SND_FLT, CM_ARG|CM_PSH },
1555 #endif /* PIPESEND */
1557 { "/followlinks", SND_LNK, 0 },
1558 #endif /* CKSYMLINK */
1560 { "/image", SND_IMG, 0 },
1562 { "/image", SND_BIN, CM_INV },
1564 { "/larger-than", SND_LAR, CM_ARG },
1565 { "/listfile", SND_FIL, CM_ARG },
1567 { "/local-character-set", SND_CSL, CM_ARG },
1568 #endif /* NOCSETS */
1570 { "/move-to", SND_MOV, CM_ARG },
1571 #endif /* CK_TMPDIR */
1572 { "/nobackupfiles", SND_NOB, 0 },
1574 { "/nodotfiles", SND_NOD, 0 },
1575 #endif /* UNIXOROSK */
1577 { "/nofollowlinks", SND_NLK, 0 },
1578 #endif /* CKSYMLINK */
1580 { "/not-after", SND_NAF, CM_ARG },
1581 { "/not-before", SND_NBE, CM_ARG },
1583 { "/permissions", SND_PRM, CM_ARG },
1585 { "/permissions", SND_PRM, CM_ARG|CM_INV },
1587 { "/quiet", SND_SHH, 0 },
1589 { "/recover", SND_RES, 0 },
1590 #endif /* FTP_RESTART */
1592 { "/recursive", SND_REC, 0 },
1593 #endif /* RECURSIVE */
1594 { "/rename-to", SND_REN, CM_ARG },
1596 { "/restart", SND_RES, CM_INV },
1597 #endif /* FTP_RESTART */
1599 { "/server-character-set", SND_CSR, CM_ARG },
1600 #endif /* NOCSETS */
1601 { "/server-rename-to", SND_SRN, CM_ARG },
1602 { "/simulate", SND_SIM, 0 },
1603 { "/since", SND_AFT, CM_INV|CM_ARG },
1604 { "/smaller-than", SND_SMA, CM_ARG },
1606 { "/starting-at", SND_STA, CM_ARG },
1607 #endif /* COMMENT */
1609 { "/subdirectories", SND_REC, CM_INV },
1610 #endif /* RECURSIVE */
1611 { "/tenex", SND_TEN, 0 },
1612 { "/text", SND_TXT, 0 },
1614 { "/transparent", SND_XPA, 0 },
1615 #endif /* NOCSETS */
1616 { "/type", SND_TYP, CM_ARG },
1618 { "/update", SND_UPD, 0 },
1619 #endif /* DOUPDATE */
1620 { "/unique-server-names", SND_USN, 0 },
1623 static int nputswi = (sizeof(putswi) / sizeof(struct keytab)) - 1;
1625 static struct keytab getswi[] = { /* FTP [M]GET switch table */
1626 { "/after", SND_AFT, CM_INV },
1627 { "/as", SND_ASN, CM_ARG|CM_INV|CM_ABR },
1628 { "/as-name", SND_ASN, CM_ARG },
1629 { "/ascii", SND_TXT, CM_INV },
1630 { "/before", SND_BEF, CM_INV },
1631 { "/binary", SND_BIN, 0 },
1632 { "/collision", SND_COL, CM_ARG },
1634 { "/command", SND_CMD, CM_PSH },
1635 #endif /* PUTPIPE */
1636 { "/delete", SND_DEL, 0 },
1637 { "/error-action", SND_ERR, CM_ARG },
1638 { "/except", SND_EXC, CM_ARG },
1639 { "/filenames", SND_NAM, CM_ARG },
1642 { "/filter", SND_FLT, CM_ARG|CM_PSH },
1644 #endif /* PIPESEND */
1646 { "/image", SND_IMG, 0 },
1648 { "/image", SND_BIN, CM_INV },
1650 { "/larger-than", SND_LAR, CM_ARG },
1651 { "/listfile", SND_FIL, CM_ARG },
1653 { "/local-character-set", SND_CSL, CM_ARG },
1654 #endif /* NOCSETS */
1655 { "/match", SND_PAT, CM_ARG },
1656 { "/ml", SND_MLS, CM_INV|CM_ABR },
1657 { "/mls", SND_MLS, CM_INV|CM_ABR },
1658 { "/mlsd", SND_MLS, 0 },
1659 { "/mlst", SND_MLS, CM_INV },
1661 { "/move-to", SND_MOV, CM_ARG },
1662 #endif /* CK_TMPDIR */
1663 { "/namelist", SND_NML, CM_ARG },
1664 { "/nlst", SND_NLS, 0 },
1665 { "/nobackupfiles", SND_NOB, 0 },
1666 { "/nodotfiles", SND_NOD, 0 },
1668 { "/dates-differ", SND_DIF, CM_INV },
1669 #endif /* DOUPDATE */
1670 { "/not-after", SND_NAF, CM_INV },
1671 { "/not-before", SND_NBE, CM_INV },
1672 { "/permissions", SND_PRM, CM_INV },
1673 { "/quiet", SND_SHH, 0 },
1675 { "/recover", SND_RES, 0 },
1676 #endif /* FTP_RESTART */
1678 { "/recursive", SND_REC, 0 },
1679 #endif /* RECURSIVE */
1680 { "/rename-to", SND_REN, CM_ARG },
1682 { "/restart", SND_RES, CM_INV },
1683 #endif /* FTP_RESTART */
1685 { "/server-character-set", SND_CSR, CM_ARG },
1686 #endif /* NOCSETS */
1687 { "/server-rename-to", SND_SRN, CM_ARG },
1688 { "/smaller-than", SND_SMA, CM_ARG },
1690 { "/subdirectories", SND_REC, CM_INV },
1691 #endif /* RECURSIVE */
1692 { "/text", SND_TXT, 0 },
1693 { "/tenex", SND_TEN, 0 },
1695 { "/transparent", SND_XPA, 0 },
1696 #endif /* NOCSETS */
1697 { "/to-screen", SND_MAI, 0 },
1699 { "/update", SND_UPD, CM_INV },
1700 #endif /* DOUPDATE */
1703 static int ngetswi = (sizeof(getswi) / sizeof(struct keytab)) - 1;
1705 static struct keytab delswi[] = { /* FTP [M]DELETE switch table */
1706 { "/error-action", SND_ERR, CM_ARG },
1707 { "/except", SND_EXC, CM_ARG },
1708 { "/filenames", SND_NAM, CM_ARG },
1709 { "/larger-than", SND_LAR, CM_ARG },
1710 { "/nobackupfiles", SND_NOB, 0 },
1712 { "/nodotfiles", SND_NOD, 0 },
1713 #endif /* UNIXOROSK */
1714 { "/quiet", SND_SHH, 0 },
1716 { "/recursive", SND_REC, 0 },
1717 #endif /* RECURSIVE */
1718 { "/smaller-than", SND_SMA, CM_ARG },
1720 { "/subdirectories", SND_REC, CM_INV },
1721 #endif /* RECURSIVE */
1724 static int ndelswi = (sizeof(delswi) / sizeof(struct keytab)) - 1;
1726 static struct keytab fntab[] = { /* Filename conversion keyword table */
1727 { "automatic", 2, CNV_AUTO },
1728 { "converted", 1, CNV_CNV },
1729 { "literal", 0, CNV_LIT }
1731 static int nfntab = (sizeof(fntab) / sizeof(struct keytab));
1733 static struct keytab ftptyp[] = { /* SET FTP TYPE table */
1734 { "ascii", FTT_ASC, 0 },
1735 { "binary", FTT_BIN, 0 },
1736 { "tenex", FTT_TEN, 0 },
1737 { "text", FTT_ASC, CM_INV },
1740 static int nftptyp = (sizeof(ftptyp) / sizeof(struct keytab)) - 1;
1743 static struct keytab ftppro[] = { /* SET FTP PROTECTION-LEVEL table */
1744 { "clear", FPL_CLR, 0 },
1745 { "confidential", FPL_CON, 0 },
1746 { "private", FPL_PRV, 0 },
1747 { "safe", FPL_SAF, 0 },
1750 static int nftppro = (sizeof(ftppro) / sizeof(struct keytab)) - 1;
1751 #endif /* FTP_SECURITY */
1753 /* Definitions for FTP from RFC765. */
1757 #define REPLY_PRELIM 1 /* Positive preliminary */
1758 #define REPLY_COMPLETE 2 /* Positive completion */
1759 #define REPLY_CONTINUE 3 /* Positive intermediate */
1760 #define REPLY_TRANSIENT 4 /* Transient negative completion */
1761 #define REPLY_ERROR 5 /* Permanent negative completion */
1762 #define REPLY_SECURE 6 /* Security encoded message */
1764 /* Form codes and names */
1766 #define FORM_N 1 /* Non-print */
1767 #define FORM_T 2 /* Telnet format effectors */
1768 #define FORM_C 3 /* Carriage control (ASA) */
1770 /* Structure codes and names */
1772 #define STRU_F 1 /* File (no record structure) */
1773 #define STRU_R 2 /* Record structure */
1774 #define STRU_P 3 /* Page structure */
1776 /* Mode types and names */
1778 #define MODE_S 1 /* Stream */
1779 #define MODE_B 2 /* Block */
1780 #define MODE_C 3 /* Compressed */
1782 /* Protection levels and names */
1784 #define PROT_C 1 /* Clear */
1785 #define PROT_S 2 /* Safe */
1786 #define PROT_P 3 /* Private */
1787 #define PROT_E 4 /* Confidential */
1789 #ifdef COMMENT /* Not used */
1791 char *strunames[] = {"0", "File", "Record", "Page" };
1792 char *formnames[] = {"0", "Nonprint", "Telnet", "Carriage-control" };
1793 char *modenames[] = {"0", "Stream", "Block", "Compressed" };
1794 char *levelnames[] = {"0", "Clear", "Safe", "Private", "Confidential" };
1795 #endif /* FTP_NAMES */
1799 #define REC_ESC '\377' /* Record-mode Escape */
1800 #define REC_EOR '\001' /* Record-mode End-of-Record */
1801 #define REC_EOF '\002' /* Record-mode End-of-File */
1805 #define BLK_EOR 0x80 /* Block is End-of-Record */
1806 #define BLK_EOF 0x40 /* Block is End-of-File */
1807 #define BLK_REPLY_ERRORS 0x20 /* Block might have errors */
1808 #define BLK_RESTART 0x10 /* Block is Restart Marker */
1809 #define BLK_BYTECOUNT 2 /* Bytes in this block */
1810 #endif /* COMMENT */
1812 #define RADIX_ENCODE 0 /* radix_encode() function codes */
1813 #define RADIX_DECODE 1
1816 The default setpbsz() value in the Unix FTP client is 1<<20 (1MB). This
1817 results in a serious performance degradation due to the increased number
1818 of page faults and the inability to overlap encrypt/decrypt, file i/o, and
1819 network i/o. So instead we set the value to 1<<13 (8K), about half the size
1820 of the typical TCP window. Maybe we should add a command to allow the value
1823 #define DEFAULT_PBSZ 1<<13
1827 _PROTOTYP(int remtxt, (char **) );
1828 _PROTOTYP(char * gskreason, (int) );
1829 _PROTOTYP(static int ftpclose,(void));
1830 _PROTOTYP(static int zzsend, (int, CHAR));
1831 _PROTOTYP(static int getreply,(int,int,int,int,int));
1832 _PROTOTYP(static int radix_encode,(CHAR[], CHAR[], int, int *, int));
1833 _PROTOTYP(static int setpbsz,(unsigned int));
1834 _PROTOTYP(static int recvrequest,(char *,char *,char *,char *,
1835 int,int,char *,int,int,int));
1836 _PROTOTYP(static int ftpcmd,(char *,char *,int,int,int));
1837 _PROTOTYP(static int fts_cpl,(int));
1838 _PROTOTYP(static int fts_dpl,(int));
1840 _PROTOTYP(static int ftp_auth, (void));
1841 #endif /* FTP_SECURITY */
1842 _PROTOTYP(static int ftp_user, (char *, char *, char *));
1843 _PROTOTYP(static int ftp_login, (char *));
1844 _PROTOTYP(static int ftp_reset, (void));
1845 _PROTOTYP(static int ftp_rename, (char *, char *));
1846 _PROTOTYP(static int ftp_umask, (char *));
1847 _PROTOTYP(static int secure_flush, (int));
1849 _PROTOTYP(static int secure_putc, (char, int));
1850 #endif /* COMMENT */
1851 _PROTOTYP(static int secure_write, (int, CHAR *, unsigned int));
1852 _PROTOTYP(static int scommand, (char *));
1853 _PROTOTYP(static int secure_putbuf, (int, CHAR *, unsigned int));
1854 _PROTOTYP(static int secure_getc, (int, int));
1855 _PROTOTYP(static int secure_getbyte, (int, int));
1856 _PROTOTYP(static int secure_read, (int, char *, int));
1857 _PROTOTYP(static int initconn, (void));
1858 _PROTOTYP(static int dataconn, (char *));
1859 _PROTOTYP(static int setprotbuf,(unsigned int));
1860 _PROTOTYP(static int sendrequest, (char *, char *, char *, int,int,int,int));
1862 _PROTOTYP(static char * radix_error,(int));
1863 _PROTOTYP(static char * ftp_hookup,(char *, int, int));
1864 _PROTOTYP(static CHAR * remote_files, (int, CHAR *, CHAR *, int));
1866 _PROTOTYP(static VOID mlsreset, (void));
1867 _PROTOTYP(static VOID secure_error, (char *fmt, ...));
1868 _PROTOTYP(static VOID lostpeer, (void));
1869 _PROTOTYP(static VOID cancel_remote, (int));
1870 _PROTOTYP(static VOID changetype, (int, int));
1872 _PROTOTYP(static sigtype cmdcancel, (int));
1875 _PROTOTYP(static int srp_reset, ());
1876 _PROTOTYP(static int srp_ftp_auth, (char *,char *,char *));
1877 _PROTOTYP(static int srp_put, (CHAR *, CHAR **, int, int *));
1878 _PROTOTYP(static int srp_get, (CHAR **, CHAR **, int *, int *));
1879 _PROTOTYP(static int srp_encode, (int, CHAR *, CHAR *, unsigned int));
1880 _PROTOTYP(static int srp_decode, (int, CHAR *, CHAR *, unsigned int));
1881 _PROTOTYP(static int srp_selcipher, (char *));
1882 _PROTOTYP(static int srp_selhash, (char *));
1883 #endif /* FTP_SRP */
1886 _PROTOTYP(static void user_gss_error,(OM_uint32, OM_uint32,char *));
1887 #endif /* FTP_GSSAPI */
1889 /* D O F T P A R G -- Do an FTP command-line argument. */
1902 #define FT_SECURE 10
1903 #define FT_VERIFY 11
1905 static struct keytab ftpztab[] = {
1906 { "!gss", FT_NOGSS, 0 },
1907 { "!krb4", FT_NOK4, 0 },
1908 { "!srp", FT_NOSRP, 0 },
1909 { "!ssl", FT_NOSSL, 0 },
1910 { "!tls", FT_NOTLS, 0 },
1911 { "cert", FT_CERTFI, CM_ARG },
1912 { "certsok", FT_OKCERT, 0 },
1913 { "debug", FT_DEBUG, 0 },
1914 { "key", FT_KEY, CM_ARG },
1915 { "nogss", FT_NOGSS, 0 },
1916 { "nokrb4", FT_NOK4, 0 },
1917 { "nosrp", FT_NOSRP, 0 },
1918 { "nossl", FT_NOSSL, 0 },
1919 { "notls", FT_NOTLS, 0 },
1921 { "secure", FT_SECURE, 0 },
1922 #endif /* COMMENT */
1923 { "verify", FT_VERIFY, CM_ARG },
1926 static int nftpztab = sizeof(ftpztab) / sizeof(struct keytab) - 1;
1929 The following cipher and hash tables should be replaced with
1930 dynamicly created versions based upon the linked library.
1932 #define SRP_BLOWFISH_ECB 1
1933 #define SRP_BLOWFISH_CBC 2
1934 #define SRP_BLOWFISH_CFB64 3
1935 #define SRP_BLOWFISH_OFB64 4
1936 #define SRP_CAST5_ECB 5
1937 #define SRP_CAST5_CBC 6
1938 #define SRP_CAST5_CFB64 7
1939 #define SRP_CAST5_OFB64 8
1940 #define SRP_DES_ECB 9
1941 #define SRP_DES_CBC 10
1942 #define SRP_DES_CFB64 11
1943 #define SRP_DES_OFB64 12
1944 #define SRP_DES3_ECB 13
1945 #define SRP_DES3_CBC 14
1946 #define SRP_DES3_CFB64 15
1947 #define SRP_DES3_OFB64 16
1949 static struct keytab ciphertab[] = {
1950 { "blowfish_ecb", SRP_BLOWFISH_ECB, 0 },
1951 { "blowfish_cbc", SRP_BLOWFISH_CBC, 0 },
1952 { "blowfish_cfb64", SRP_BLOWFISH_CFB64, 0 },
1953 { "blowfish_ofb64", SRP_BLOWFISH_OFB64, 0 },
1954 { "cast5_ecb", SRP_CAST5_ECB, 0 },
1955 { "cast5_cbc", SRP_CAST5_CBC, 0 },
1956 { "cast5_cfb64", SRP_CAST5_CFB64, 0 },
1957 { "cast5_ofb64", SRP_CAST5_OFB64, 0 },
1958 { "des_ecb", SRP_DES_ECB, 0 },
1959 { "des_cbc", SRP_DES_CBC, 0 },
1960 { "des_cfb64", SRP_DES_CFB64, 0 },
1961 { "des_ofb64", SRP_DES_OFB64, 0 },
1962 { "des3_ecb", SRP_DES3_ECB, 0 },
1963 { "des3_cbc", SRP_DES3_CBC, 0 },
1964 { "des3_cfb64", SRP_DES3_CFB64, 0 },
1965 { "des3_ofb64", SRP_DES3_OFB64, 0 },
1969 static int nciphertab = sizeof(ciphertab) / sizeof(struct keytab) - 1;
1973 static struct keytab hashtab[] = {
1974 { "md5", SRP_MD5, 0 },
1976 { "sha", SRP_SHA, 0 },
1979 static int nhashtab = sizeof(hashtab) / sizeof(struct keytab) - 1;
1981 #endif /* FTP_SECURITY */
1984 strval(s1,s2) char * s1, * s2; {
1987 return(*s1 ? s1 : (*s2 ? s2 : "(none)"));
1991 static char * rfnptr = NULL;
1992 static int rfnlen = 0;
1993 static char rfnbuf[RFNBUFSIZ]; /* Remote filename translate buffer */
1994 static char * xgnbp = NULL;
1997 strgetc() { /* Helper function for xgnbyte() */
2003 c = (unsigned) *xgnbp++;
2004 return(((unsigned) c) & 0xff);
2007 static int /* Helper function for xpnbyte() */
2012 #endif /* CK_ANSIC */
2014 rfnlen = rfnptr - rfnbuf;
2015 if (rfnlen >= (RFNBUFSIZ - 1))
2027 #endif /* CK_ANSIC */
2034 bytswap(c0,c1) int * c0, * c1; {
2040 #endif /* NOCSETS */
2043 char ftplogbuf[CXLOGBUFL] = { NUL, NUL }; /* Connection Log */
2044 int ftplogactive = 0;
2045 long ftplogprev = 0L;
2050 extern char diafil[];
2051 long d1, d2, t1, t2;
2054 debug(F111,"ftp cx log active",ckitoa(dialog),ftplogactive);
2055 debug(F110,"ftp cx log buf",ftplogbuf,0);
2057 if (!ftplogactive || !ftplogbuf[0]) /* No active record */
2060 ftplogactive = 0; /* Record is not active */
2062 d1 = mjd((char *)ftplogbuf); /* Get start date of this session */
2063 ckstrncpy(buf,ckdate(),31); /* Get current date */
2064 d2 = mjd(buf); /* Convert them to mjds */
2065 p = ftplogbuf; /* Get start time */
2067 p[14] = NUL; /* Convert to seconds */
2068 t1 = atol(p+9) * 3600L + atol(p+12) * 60L + atol(p+15);
2071 p = buf; /* Get end time */
2074 t2 = atol(p+9) * 3600L + atol(p+12) * 60L + atol(p+15);
2075 t2 = ((d2 - d1) * 86400L) + (t2 - t1); /* Compute elapsed time */
2079 ckstrncat(ftplogbuf,"E=",CXLOGBUFL); /* Append to log record */
2080 ckstrncat(ftplogbuf,p,CXLOGBUFL);
2083 debug(F101,"ftp cx log dialog","",dialog);
2084 if (dialog) { /* If logging */
2086 x = diaopn(diafil,1,1); /* Open log in append mode */
2088 debug(F101,"ftp cx log open","",x);
2089 x = zsoutl(ZDIFIL,ftplogbuf); /* Write the record */
2090 debug(F101,"ftp cx log write","",x);
2091 x = zclose(ZDIFIL); /* Close the log */
2092 debug(F101,"ftp cx log close","",x);
2099 ftplogend(); /* Previous session not closed out? */
2101 ftplogactive = 1; /* Record is active */
2103 ckmakxmsg(ftplogbuf,CXLOGBUFL,
2104 ckdate()," ",strval(ftp_logname,NULL)," ",ckgetpid(),
2105 " T=FTP N=", strval(ftp_host,NULL)," H=",myhost,
2106 " P=", ckitoa(ftp_port)," "); /* SMS 2007/02/15 */
2107 debug(F110,"ftp cx log begin",ftplogbuf,0);
2109 #endif /* CKLOGDIAL */
2111 static char * dummy[2] = { NULL, NULL };
2113 static struct keytab modetab[] = {
2119 int /* Called from ckuusy.c */
2124 #endif /* CK_ANSIC */
2128 extern char **xargv, *xarg0;
2129 extern int xargc, stayflg, haveftpuid;
2130 extern char uidbuf[];
2132 xp = *xargv+1; /* Pointer for bundled args */
2134 if (ckstrchr("MuDPkcHzm",c)) { /* Options that take arguments */
2136 fatal("?Invalid argument bundling");
2139 if ((xargc < 1) || (**xargv == '-')) {
2140 fatal("?Required argument missing");
2143 switch (c) { /* Big switch on arg */
2144 case 'h': /* help */
2145 printf("C-Kermit's FTP client command-line personality. Usage:\n");
2146 printf(" %s [ options ] host [ port ] [-pg files ]\n\n",xarg0);
2147 printf("Options:\n");
2148 printf(" -h = help (this message)\n");
2149 printf(" -m mode = \"passive\" (default) or \"active\"\n");
2150 printf(" -u name = username for autologin (or -M)\n");
2151 printf(" -P password = password for autologin (RISKY)\n");
2152 printf(" -A = autologin anonymously\n");
2153 printf(" -D directory = cd after autologin\n");
2154 printf(" -b = force binary mode\n");
2155 printf(" -a = force text (\"ascii\") mode (or -T)\n");
2156 printf(" -d = debug (double to add timestamps)\n");
2157 printf(" -n = no autologin\n");
2158 printf(" -v = verbose (default)\n");
2159 printf(" -q = quiet\n");
2160 printf(" -S = Stay (issue command prompt when done)\n");
2161 printf(" -Y = do not execute Kermit init file\n");
2162 printf(" -p files = files to put after autologin (or -s)\n");
2163 printf(" -g files = files to get after autologin\n");
2164 printf(" -R = recursive (for use with -p)\n");
2167 printf("\nSecurity options:\n");
2168 printf(" -k realm = Kerberos 4 realm\n");
2169 printf(" -f = Kerboros 5 credentials forwarding\n");
2170 printf(" -x = autoencryption mode\n");
2171 printf(" -c cipher = SRP cipher type\n");
2172 printf(" -H hash = SRP encryption hash\n");
2173 printf(" -z option = Security options\n");
2174 #endif /* FTP_SECURITY */
2176 printf("\n-p or -g, if given, should be last. Example:\n");
2177 printf(" ftp -A kermit.columbia.edu -D kermit -ag TESTFILE\n");
2179 doexit(GOOD_EXIT,-1);
2182 case 'R': /* Recursive */
2186 case 'd': /* Debug */
2192 deblog = debopn("debug.log",0);
2196 /* fall thru on purpose */
2198 case 't': /* Trace */
2202 case 'n': /* No autologin */
2206 case 'i': /* No prompt */
2207 case 'v': /* Verbose */
2208 break; /* (ignored) */
2210 case 'q': /* Quiet */
2214 case 'S': /* Stay */
2219 case 'u': /* My User Name */
2220 if ((int)strlen(*xargv) > 63) {
2221 fatal("username too long");
2223 ckstrncpy(uidbuf,*xargv,UIDBUFLEN);
2228 ckstrncpy(uidbuf,"anonymous",UIDBUFLEN);
2232 case 'T': /* Text */
2233 case 'a': /* "ascii" */
2234 case 'b': /* Binary */
2235 binary = (c == 'b') ? FTT_BIN : FTT_ASC;
2236 ftp_xfermode = XMODE_M;
2243 case 's': { /* Send (= Put) */
2246 fatal("Only one FTP action at a time please");
2249 fatal("invalid argument bundling after -s");
2251 nfils = 0; /* Initialize file counter */
2252 havefiles = 0; /* Assume nothing to send */
2253 cmlist = xargv + 1; /* Remember this pointer */
2255 while (++xargv, --xargc > 0) { /* Traverse the list */
2262 if (!strcmp(*xargv,".")) {
2267 #endif /* RECURSIVE */
2268 if ((rc = zchki(*xargv)) > -1 || (rc == -2)) {
2272 } else if (iswild(*xargv) && nzxpand(*xargv,0) > 0) {
2277 xargc++, xargv--; /* Adjust argv/argc */
2280 fatal("No files to put");
2282 fatal("No files to get");
2288 case 'D': /* Directory */
2289 makestr(&ftp_rdir,*xargv);
2292 case 'm': /* Mode (Active/Passive */
2293 ftp_psv = lookup(modetab,*xargv,2,NULL);
2294 if (ftp_psv < 0) fatal("Invalid mode");
2298 makestr(&ftp_tmp,*xargv); /* You-Know-What */
2301 case 'Y': /* No initialization file */
2302 break; /* (already done in prescan) */
2305 case 'U': { /* URL */
2306 /* These are set by urlparse() - any not set are NULL */
2309 Kermit has accepted host:port notation since many years before URLs were
2310 invented. Unfortunately, URLs conflict with this notation. Thus "ftp
2311 host:449" looks like a URL and results in service = host and host = 449.
2312 Here we try to catch this situation transparently to the user.
2314 if (ckstrcmp(g_url.svc,"ftp",-1,0)
2316 && ckstrcmp(g_url.svc,"ftps",-1,0)
2323 g_url.por = g_url.hos;
2324 g_url.hos = g_url.svc;
2327 ckmakmsg(tmpbuf,TMPBUFSIZ,"Non-FTP URL: service=",
2328 g_url.svc," host=",g_url.hos);
2332 makestr(&ftp_host,g_url.hos);
2335 ckstrncpy(uidbuf,g_url.usr,UIDBUFLEN);
2336 makestr(&ftp_logname,uidbuf);
2339 makestr(&ftp_tmp,g_url.psw);
2344 ckstrncpy(uidbuf,"anonymous",UIDBUFLEN);
2345 makestr(&ftp_logname,uidbuf);
2348 fatal("Only one FTP action at a time please");
2353 dummy[0] = g_url.pth;
2365 case 'k': { /* K4 Realm */
2367 ckstrncpy(ftp_realm,*xargv, REALM_SZ);
2368 #endif /* FTP_KRB4 */
2369 if (ftp_deb) printf("K4 Realm = [%s]\n",*xargv);
2375 if (ftp_deb) printf("K5 Credentials Forwarding\n");
2376 #else /* FTP_GSSAPI */
2377 printf("K5 Credentials Forwarding not supported\n");
2378 #endif /* FTP_GSSAPI */
2383 if (ftp_deb) printf("Autoencryption\n");
2386 case 'c': { /* Cipher */
2388 if (!srp_selcipher(*xargv)) {
2389 if (ftp_deb) printf("SRP cipher type: \"%s\"\n",*xargv);
2391 printf("?Invalid SRP cipher type: \"%s\"\n",*xargv);
2393 printf("?SRP not supported\n");
2394 #endif /* FTP_SRP */
2399 if (!srp_selhash(*xargv)) {
2400 if (ftp_deb) printf("SRP hash type: \"%s\"\n",*xargv);
2402 printf("?Invalid SRP hash type: \"%s\"\n",*xargv);
2404 printf("?SRP not supported\n");
2405 #endif /* FTP_SRP */
2409 /* *xargv contains a value of the form tag=value */
2410 /* we need to lookup the tag and save the value */
2411 char * p = NULL, * q = NULL;
2413 y = ckindex("=",p,0,0,1);
2416 x = lookup(ftpztab,p,nftpztab,&z);
2418 printf("?Invalid security option: \"%s\"\n",p);
2421 printf("Security option: \"%s",p);
2422 if (ftpztab[z].flgs & CM_ARG) {
2424 fatal("?Missing required value");
2427 fatal("?Missing required value");
2431 switch (ftpztab[z].kwval) { /* -z options w/args */
2434 for (z = 0; z < FTPATYPS && ftp_auth_type[z]; z++) {
2435 if (ftp_auth_type[z] == FTA_GK5) {
2437 y < (FTPATYPS-1) && ftp_auth_type[y];
2440 ftp_auth_type[y] = ftp_auth_type[y+1];
2441 ftp_auth_type[FTPATYPS-1] = 0;
2445 #endif /* FTP_GSSAPI */
2449 for (z = 0; z < FTPATYPS && ftp_auth_type[z]; z++) {
2450 if (ftp_auth_type[z] == FTA_K4) {
2452 y < (FTPATYPS-1) && ftp_auth_type[y];
2455 ftp_auth_type[y] = ftp_auth_type[y+1];
2456 ftp_auth_type[FTPATYPS-1] = 0;
2460 #endif /* FTP_KRB4 */
2464 for (z = 0; z < FTPATYPS && ftp_auth_type[z]; z++) {
2465 if (ftp_auth_type[z] == FTA_SRP) {
2467 y < (FTPATYPS-1) && ftp_auth_type[y];
2470 ftp_auth_type[y] = ftp_auth_type[y+1];
2471 ftp_auth_type[FTPATYPS-1] = 0;
2475 #endif /* FTP_SRP */
2479 for (z = 0; z < FTPATYPS && ftp_auth_type[z]; z++) {
2480 if (ftp_auth_type[z] == FTA_SSL) {
2482 y < (FTPATYPS-1) && ftp_auth_type[y];
2485 ftp_auth_type[y] = ftp_auth_type[y+1];
2486 ftp_auth_type[FTPATYPS-1] = 0;
2494 for (z = 0; z < FTPATYPS && ftp_auth_type[z]; z++) {
2495 if (ftp_auth_type[z] == FTA_TLS) {
2497 y < (FTPATYPS-1) && ftp_auth_type[y];
2500 ftp_auth_type[y] = ftp_auth_type[y+1];
2501 ftp_auth_type[FTPATYPS-1] = 0;
2509 makestr(&ssl_rsa_cert_file,q);
2514 ssl_certsok_flag = 1;
2523 deblog = debopn("debug.log",0);
2529 makestr(&ssl_rsa_key_file,q);
2538 printf("?Bad number: %s\n",q);
2539 ssl_verify_flag = atoi(q);
2544 if (ftp_deb) printf("\"\n");
2548 #endif /* FTP_SECURITY */
2552 "unknown command-line option, type \"ftp -h\" for help"
2556 c = *++xp; /* See if options are bundled */
2569 return(connected ? loggedin : 0);
2574 return((ftp_dpl == FPL_CLR && !ssl_ftp_proxy) ? 0 : 1);
2578 ftscreen(n, c, z, s) int n; char c; CK_OFF_T z; char * s; {
2579 if (displa && fdispla && !backgrd && !quiet && !out2screen) {
2581 ckscreen(SCR_PT,'S',(CK_OFF_T)0,"");
2589 /* g m s t i m e r -- Millisecond timer */
2594 /* For those versions of ztime() that also set global ztmsec. */
2599 if (!*p) return(0L);
2600 z = atol(p+11) * 3600L + atol(p+14) * 60L + atol(p+17);
2601 return(z * 1000 + ztmsec);
2603 return((long)time(NULL) * 1000L);
2604 #endif /* HAVE_MSECS */
2608 /* d o s e t f t p -- The SET FTP command */
2613 if ((cx = cmkey(ftpset,nftpset,"","",xxstring)) < 0) /* Set what? */
2617 case FTS_FNC: /* Filename collision action */
2618 if ((x = cmkey(ftpcolxtab,nftpcolx,"","",xxstring)) < 0)
2620 if ((y = cmcfm()) < 0)
2625 case FTS_CNV: /* Filename conversion */
2626 if ((x = cmkey(fntab,nfntab,"","automatic",xxstring)) < 0)
2628 if ((y = cmcfm()) < 0)
2633 case FTS_DBG: /* Debug messages */
2634 return(seton(&ftp_deb));
2636 case FTS_LOG: /* Auto-login */
2637 return(seton(&ftp_log));
2639 case FTS_PSV: /* Passive mode */
2640 return(dosetftppsv());
2642 case FTS_SPC: /* Send port commands */
2643 x = seton(&ftp_spc);
2644 if (x > 0) sendport = ftp_spc;
2647 case FTS_TYP: /* Type */
2648 if ((x = cmkey(ftptyp,nftptyp,"","",xxstring)) < 0)
2650 if ((y = cmcfm()) < 0) return(y);
2653 tenex = (ftp_typ == FTT_TEN);
2656 case FTS_USN: /* Unique server names */
2657 return(seton(&ftp_usn));
2659 case FTS_VBM: /* Verbose mode */
2660 if ((x = seton(&ftp_vbm)) < 0) /* Per-command copy */
2662 ftp_vbx = ftp_vbm; /* Global sticky copy */
2665 case FTS_TST: /* "if (testing)" messages */
2666 return(seton(&testing));
2668 case FTS_PRM: /* Send permissions */
2669 return(setonaut(&ftp_prm));
2671 case FTS_AUT: /* Auto-authentication */
2672 return(seton(&ftp_aut));
2674 case FTS_ERR: /* Error action */
2675 if ((x = cmkey(qorp,2,"","",xxstring)) < 0)
2677 if ((y = cmcfm()) < 0)
2680 return(success = 1);
2683 case FTS_XLA: /* Translation */
2684 return(seton(&ftp_xla));
2686 case FTS_CSR: /* Server charset */
2687 if ((x = cmkey(fcstab,nfilc,"character-set","utf8",xxstring)) < 0)
2689 if ((y = cmcfm()) < 0)
2692 ftp_xla = 1; /* Also enable translation */
2693 return(success = 1);
2694 #endif /* NOCSETS */
2697 return(seton(&get_auto)); /* GET-filetype-switching */
2700 return(seton(&ftp_dates)); /* Set file dates */
2703 case FTS_TMO: /* Timeout */
2704 if ((x = cmnum("Number of seconds","0",10,&z,xxstring)) < 0)
2706 if ((y = cmcfm()) < 0)
2709 return(success = 1);
2710 #endif /* FTP_TIMEOUT */
2712 case FTS_STO: { /* Server time offset */
2713 char * s, * p = NULL;
2715 if ((x = cmfld("[+-]hh[:mm[:ss]]","+0",&s,xxstring)) < 0)
2717 if (!strcmp(s,"+0")) {
2719 } else if ((x = delta2sec(s,&k)) < 0) { /* Check format */
2720 printf("?Invalid time offset\n");
2723 makestr(&p,s); /* Make a safe copy the string */
2724 if ((x = cmcfm()) < 0) { /* Get confirmation */
2729 fts_sto = p; /* Confirmed - set the string. */
2730 return(success = 1);
2734 if ((x = cmtxt("Text", "", &s, xxstring)) < 0)
2736 makestr(&ftp_apw, *s ? s : NULL);
2737 return(success = 1);
2741 if ((x = cmkey(ftpbugtab,nftpbug,"","",xxstring)) < 0)
2746 return seton(&ftp_bug_use_ssl_v2);
2754 case FTS_CRY: /* Auto-encryption */
2755 return(seton(&ftp_cry));
2757 case FTS_CFW: /* Credential-forwarding */
2758 return(seton(&ftp_cfw));
2760 case FTS_CPL: /* Command protection level */
2761 if ((x = cmkey(ftppro,nftppro,"","",xxstring)) < 0) return(x);
2762 if ((y = cmcfm()) < 0) return(y);
2763 success = fts_cpl(x);
2766 case FTS_DPL: /* Data protection level */
2767 if ((x = cmkey(ftppro,nftppro,"","",xxstring)) < 0) return(x);
2768 if ((y = cmcfm()) < 0) return(y);
2769 success = fts_dpl(x);
2772 case FTS_ATP: { /* FTP Auth Type */
2773 int i, j, atypes[8];
2775 for (i = 0; i < 8; i++) {
2776 if ((y = cmkey(ftpauth,nftpauth,"",
2777 (i == 0) ? "automatic" : "",
2783 if (i > 0 && (y == FTA_AUTO)) {
2784 printf("?Choice may only be used in first position.\r\n");
2787 for (j = 0; j < i; j++) {
2788 if (atypes[j] == y) {
2789 printf("\r\n?Choice has already been used.\r\n");
2794 if (y == FTA_AUTO) {
2801 if ((z = cmcfm()) < 0)
2803 if (atypes[0] == FTA_AUTO) {
2806 ftp_auth_type[i++] = FTA_GK5;
2807 #endif /* FTP_GSSAPI */
2809 ftp_auth_type[i++] = FTA_SRP;
2810 #endif /* FTP_SRP */
2812 ftp_auth_type[i++] = FTA_K4;
2813 #endif /* FTP_KRB4 */
2815 ftp_auth_type[i++] = FTA_TLS;
2816 ftp_auth_type[i++] = FTA_SSL;
2818 ftp_auth_type[i] = 0;
2820 for (i = 0; i < 8; i++)
2821 ftp_auth_type[i] = atypes[i];
2823 return(success = 1);
2828 if ((x = cmkey(ftpsrp,nftpsrp,"","",xxstring)) < 0)
2832 if ((x = cmkey(ciphertab,nciphertab,"","",xxstring)) < 0)
2834 if ((z = cmcfm()) < 0)
2836 success = !srp_selcipher(ciphertab[x].kwd);
2839 if ((x = cmkey(hashtab,nhashtab,"","",xxstring)) < 0)
2841 if ((z = cmcfm()) < 0)
2843 success = !srp_selhash(hashtab[x].kwd);
2844 return(success = 1);
2846 if ((z = cmcfm()) < 0)
2851 if ((z = cmcfm()) < 0)
2854 #endif /* FTP_SRP */
2855 #endif /* FTP_SECURITY */
2858 doxdis(2); /* 2 == ftp */
2859 return(success = 1);
2872 printf(" ftp closing %s...\n",ftp_host);
2874 return((x > -1) ? 1 : 0);
2877 /* o p e n f t p -- Parse FTP hostname & port and open */
2880 openftp(s,opn_tls) char * s; int opn_tls; {
2881 char c, * p, * hostname = NULL, *hostsave = NULL, * service = NULL;
2882 int i, n, havehost = 0, getval = 0, rc = -9, opn_psv = -1, nologin = 0;
2884 struct FDB sw, fl, cm;
2885 extern int nnetdir; /* Network services directory */
2886 extern int nhcount; /* Lookup result */
2887 extern char *nh_p[]; /* Network directory entry pointers */
2888 extern char *nh_p2[]; /* Network directory entry nettype */
2891 if (!*s) return(-2);
2893 makestr(&hostname,s);
2894 hostsave = hostname;
2895 makestr(&ftp_logname,NULL);
2899 debug(F110,"ftp open",hostname,0);
2901 if (sav_psv > -1) { /* Restore prevailing active/passive */
2902 ftp_psv = sav_psv; /* selection in case it was */
2903 sav_psv = -1; /* temporarily overriden by a switch */
2905 if (sav_log > -1) { /* Ditto for autologin */
2909 cmfdbi(&sw, /* Switches */
2911 "Service name or port;\n or switch",
2913 "", /* addtl string data */
2914 nftpswi, /* addtl numeric data 1: tbl size */
2915 4, /* addtl numeric data 2: none */
2916 xxstring, /* Processing function */
2917 ftpswitab, /* Keyword table */
2918 &fl /* Pointer to next FDB */
2920 cmfdbi(&fl, /* A host name or address */
2923 "xYzBoo", /* default */
2924 "", /* addtl string data */
2925 0, /* addtl numeric data 1 */
2926 0, /* addtl numeric data 2 */
2931 cmfdbi(&cm, /* Command confirmation */
2944 rc = cmfdb(&sw); /* Parse a service name or a switch */
2948 if (cmresult.fcode == _CMCFM) { /* Done? */
2950 } else if (cmresult.fcode == _CMFLD) { /* Port */
2951 if (ckstrcmp("xYzBoo",cmresult.sresult,-1,1))
2952 makestr(&service,cmresult.sresult);
2954 makestr(&service,opn_tls?"ftps":"ftp");
2955 } else if (cmresult.fcode == _CMKEY) { /* Have a switch */
2956 c = cmgbrk(); /* get break character */
2957 getval = (c == ':' || c == '=');
2959 if (getval && !(cmresult.kflags & CM_ARG)) {
2960 printf("?This switch does not take arguments\n");
2963 if (!getval && (cmresult.kflags & CM_ARG)) {
2964 printf("?This switch requires an argument\n");
2967 switch (cmresult.nresult) { /* Switch */
2968 case OPN_ANO: /* /ANONYMOUS */
2972 case OPN_NIN: /* /NOINIT */
2975 case OPN_NOL: /* /NOLOGIN */
2978 makestr(&ftp_logname,NULL);
2980 case OPN_PSW: /* /PASSWORD */
2981 if (!anonymous) /* Don't log real passwords */
2983 rc = cmfld("Password for FTP server","",&p,xxstring);
2985 makestr(&ftp_tmp,NULL);
2986 } else if (rc < 0) {
2989 makestr(&ftp_tmp,brstrip(p));
2993 case OPN_USR: /* /USER */
2994 rc = cmfld("Username for FTP server","",&p,xxstring);
2996 makestr(&ftp_logname,NULL);
2997 } else if (rc < 0) {
3003 makestr(&ftp_logname,brstrip(p));
3007 rc = cmfld("Account for FTP server","",&p,xxstring);
3009 makestr(&ftp_acc,NULL);
3010 } else if (rc < 0) {
3013 makestr(&ftp_acc,brstrip(p));
3029 if (n == 0) { /* After first time through */
3030 cmfdbi(&sw, /* accept only switches */
3032 "\nCarriage return to confirm to command, or switch",
3044 debug(F100,"ftp openftp while exit","",0);
3046 debug(F101,"ftp openftp cmcfm rc","",rc);
3049 #endif /* COMMENT */
3051 if (opn_psv > -1) { /* /PASSIVE or /ACTIVE switch given */
3055 if (nologin || haveuser) { /* /NOLOGIN or /USER switch given */
3057 ftp_log = haveuser ? 1 : 0;
3059 if (*hostname == '=') { /* Bypass directory lookup */
3060 hostname++; /* if hostname starts with '=' */
3062 } else if (isdigit(*hostname)) { /* or if it starts with a digit */
3066 makestr(&service,opn_tls?"ftps":"ftp");
3069 if (!havehost && nnetdir > 0) { /* If there is a networks directory */
3070 lunet(hostname); /* Look up the name */
3071 debug(F111,"ftp openftp lunet",hostname,nhcount);
3074 printf(" ftp open trying \"%s %s\"...\n",hostname,service);
3075 success = ftpopen(hostname,service,opn_tls);
3076 debug(F101,"ftp openftp A ftpopen success","",success);
3080 for (i = 0; i < nhcount; i++) {
3081 if (nh_p2[i]) /* If network type specified */
3082 if (ckstrcmp(nh_p2[i],"tcp/ip",strlen(nh_p2[i]),0))
3085 makestr(&hostname,nh_p[i]);
3086 debug(F111,"ftpopen lunet substitution",hostname,i);
3088 printf(" ftp open trying \"%s %s\"...\n",hostname,service);
3089 success = ftpopen(hostname,service,opn_tls);
3090 debug(F101,"ftp openftp B ftpopen success","",success);
3095 if (!found) { /* E.g. if no network types match */
3097 printf(" ftp open trying \"%s %s\"...\n",hostname,service);
3098 success = ftpopen(hostname,service,opn_tls);
3099 debug(F101,"ftp openftp C ftpopen success","",success);
3106 printf(" ftp open trying \"%s %s\"...\n",hostname,service);
3107 success = ftpopen(hostname,service,opn_tls);
3108 debug(F111,"ftp openftp D ftpopen success",hostname,success);
3109 debug(F111,"ftp openftp D ftpopen connected",hostname,connected);
3116 debug(F101,"ftp openftp xopenftp rc","",rc);
3117 if (hostsave) free(hostsave);
3118 if (service) free(service);
3119 if (rc < 0 && ftp_logname) {
3130 VOID /* 12 Aug 2007 */
3131 doftpglobaltype(x) int x; {
3132 ftp_xfermode = XMODE_M; /* Set manual FTP transfer mode */
3133 ftp_typ = x; /* Used by top-level BINARY and */
3134 g_ftp_typ = x; /* ASCII commands. */
3143 if ((x = cmtxt("Remote account", "", &s, xxstring)) < 0)
3146 makestr(&ftp_acc,brstrip(s));
3148 printf(" ftp account: \"%s\"\n",ftp_acc);
3149 success = (ftpcmd("ACCT",ftp_acc,-1,-1,ftp_vbm) == REPLY_COMPLETE);
3154 doftpusr() { /* Log in as USER */
3155 extern char uidbuf[];
3156 extern char pwbuf[];
3157 extern int pwflg, pwcrypt;
3159 char *s, * acct = "";
3161 debok = 0; /* Don't log */
3163 if ((x = cmfld("Remote username or ID",uidbuf,&s,xxstring)) < 0)
3165 ckstrncpy(line,brstrip(s),LINBUFSIZ); /* brstrip: 15 Jan 2003 */
3166 if ((x = cmfld("Remote password","",&s,xxstring)) < 0) {
3167 if (x == -3) { /* no input */
3168 if ( pwbuf[0] && pwflg ) {
3169 ckstrncpy(tmpbuf,(char *)pwbuf,TMPBUFSIZ);
3172 ck_encrypt((char *)tmpbuf);
3179 ckstrncpy(tmpbuf,brstrip(s),TMPBUFSIZ);
3181 if ((x = cmtxt("Remote account\n or Enter or CR to confirm the command",
3182 "", &s, xxstring)) < 0)
3188 acct = &tmpbuf[x+2];
3189 ckstrncpy(acct,brstrip(s),TMPBUFSIZ - x - 2);
3193 printf(" ftp user \"%s\" password \"%s\"...\n",line,tmpbuf);
3194 success = ftp_user(line,tmpbuf,acct);
3197 #endif /* CKLOGDIAL */
3201 /* DO (various FTP commands)... */
3204 doftptyp(type) int type; { /* TYPE */
3207 changetype(ftp_typ,ftp_vbm);
3208 debug(F101,"doftptyp changed type","",type);
3213 doftpxmkd(s,vbm) char * s; int vbm; { /* MKDIR action */
3214 int lcs = -1, rcs = -1;
3218 if (lcs < 0) lcs = fcharset;
3220 if (rcs < 0) rcs = ftp_csr;
3222 #endif /* NOCSETS */
3223 debug(F110,"ftp doftpmkd",s,0);
3224 if (ftpcmd("MKD",s,lcs,rcs,vbm) == REPLY_COMPLETE)
3225 return(success = 1);
3226 if (ftpcode == 500 || ftpcode == 502) {
3228 printf("MKD command not recognized, trying XMKD\n");
3229 if (ftpcmd("XMKD",s,lcs,rcs,vbm) == REPLY_COMPLETE)
3230 return(success = 1);
3232 return(success = 0);
3236 doftpmkd() { /* MKDIR parse */
3239 if ((x = cmtxt("Remote directory name", "", &s, xxstring)) < 0)
3242 ckstrncpy(line,s,LINBUFSIZ);
3244 printf(" ftp mkdir \"%s\"...\n",line);
3245 return(success = doftpxmkd(line,-1));
3249 doftprmd() { /* RMDIR */
3250 int x, lcs = -1, rcs = -1;
3252 if ((x = cmtxt("Remote directory", "", &s, xxstring)) < 0)
3255 ckstrncpy(line,s,LINBUFSIZ);
3257 printf(" ftp rmdir \"%s\"...\n",line);
3261 if (lcs < 0) lcs = fcharset;
3263 if (rcs < 0) rcs = ftp_csr;
3265 #endif /* NOCSETS */
3266 if (ftpcmd("RMD",line,lcs,rcs,ftp_vbm) == REPLY_COMPLETE)
3267 return(success = 1);
3268 if (ftpcode == 500 || ftpcode == 502) {
3270 printf("RMD command not recognized, trying XMKD\n");
3271 success = (ftpcmd("XRMD",line,lcs,rcs,ftp_vbm) == REPLY_COMPLETE);
3278 doftpren() { /* RENAME */
3281 if ((x = cmfld("Remote filename","",&s,xxstring)) < 0)
3283 ckstrncpy(line,s,LINBUFSIZ);
3284 if ((x = cmfld("New name for remote file","",&s,xxstring)) < 0)
3286 ckstrncpy(tmpbuf,s,TMPBUFSIZ);
3287 if ((x = cmcfm()) < 0)
3291 printf(" ftp rename \"%s\" (to) \"%s\"...\n",line,tmpbuf);
3292 success = ftp_rename(line,tmpbuf);
3297 doftpres() { /* RESET (log out without close) */
3299 if ((x = cmcfm()) < 0)
3303 printf(" ftp reset...\n");
3304 return(success = ftp_reset());
3308 doftpxhlp() { /* HELP */
3311 if ((x = cmtxt("Command name", "", &s, xxstring)) < 0)
3314 ckstrncpy(line,s,LINBUFSIZ);
3316 printf(" ftp help \"%s\"...\n",line);
3317 /* No need to translate -- all FTP commands are ASCII */
3318 return(success = (ftpcmd("HELP",line,0,0,1) == REPLY_COMPLETE));
3322 doftpdir(cx) int cx; { /* [V]DIRECTORY */
3323 int x, lcs = 0, rcs = 0, xlate = 0;
3324 char * p, * s, * m = "";
3325 if (cx == FTP_VDI) {
3326 switch (servertype) {
3337 if ((x = cmtxt("Remote filespec",m,&s,xxstring)) < 0)
3339 if ((x = remtxt(&s)) < 0)
3345 #endif /* NOCSETS */
3347 ckstrncpy(line,s,LINBUFSIZ);
3352 if (xlate) { /* SET FTP CHARACTER-SET-TRANSLATION */
3353 lcs = ftp_csl; /* Local charset */
3354 if (lcs < 0) lcs = fcharset;
3355 if (lcs < 0) xlate = 0;
3357 if (xlate) { /* Still ON? */
3358 rcs = ftp_csx; /* Remote (Server) charset */
3359 if (rcs < 0) rcs = ftp_csr;
3360 if (rcs < 0) xlate = 0;
3362 #endif /* NOCSETS */
3368 printf("Directory of files %s at %s:\n", line, ftp_host);
3370 printf("Directory of files at %s:\n", ftp_host);
3372 debug(F111,"doftpdir",s,cx);
3374 if (cx == FTP_DIR) {
3375 /* Translation of line[] is done inside recvrequest() */
3376 /* when it calls ftpcmd(). */
3378 (recvrequest("LIST","-",s,"wb",0,0,NULL,xlate,lcs,rcs) == 0));
3380 success = 1; /* VDIR - one file at a time... */
3381 p = (char *)remote_files(1,(CHAR *)s,NULL,0); /* Get the file list */
3383 if (!ftp_vbm && !quiet)
3385 while (p && !cancelfile && !cancelgroup) { /* STAT one file */
3386 if (ftpcmd("STAT",p,lcs,rcs,ftp_vbm) < 0) {
3390 p = (char *)remote_files(0,NULL,NULL,0); /* Get next file */
3391 debug(F110,"ftp vdir file",s,0);
3397 doftppwd() { /* PWD */
3398 int x, lcs = -1, rcs = -1;
3402 if (lcs < 0) lcs = fcharset;
3404 if (rcs < 0) rcs = ftp_csr;
3406 #endif /* NOCSETS */
3407 if ((x = cmcfm()) < 0)
3410 if (ftpcmd("PWD",NULL,lcs,rcs,1) == REPLY_COMPLETE) {
3412 } else if (ftpcode == 500 || ftpcode == 502) {
3414 printf("PWD command not recognized, trying XPWD\n");
3415 success = (ftpcmd("XPWD",NULL,lcs,rcs,1) == REPLY_COMPLETE);
3421 doftpcwd(s,vbm) char * s; int vbm; { /* CD (CWD) */
3422 int lcs = -1, rcs = -1;
3426 if (lcs < 0) lcs = fcharset;
3428 if (rcs < 0) rcs = ftp_csr;
3430 #endif /* NOCSETS */
3432 debug(F110,"ftp doftpcwd",s,0);
3433 if (ftpcmd("CWD",s,lcs,rcs,vbm) == REPLY_COMPLETE)
3434 return(success = 1);
3435 if (ftpcode == 500 || ftpcode == 502) {
3437 printf("CWD command not recognized, trying XCWD\n");
3438 if (ftpcmd("XCWD",s,lcs,rcs,vbm) == REPLY_COMPLETE)
3439 return(success = 1);
3441 return(success = 0);
3445 doftpcdup() { /* CDUP */
3446 debug(F100,"ftp doftpcdup","",0);
3447 if (ftpcmd("CDUP",NULL,0,0,1) == REPLY_COMPLETE)
3448 return(success = 1);
3449 if (ftpcode == 500 || ftpcode == 502) {
3451 printf("CDUP command not recognized, trying XCUP\n");
3452 if (ftpcmd("XCUP",NULL,0,0,1) == REPLY_COMPLETE)
3453 return(success = 1);
3455 return(success = 0);
3458 /* s y n c d i r -- Synchronizes client & server directories */
3462 local = pointer to pathname of local file to be sent.
3463 sim = 1 for simulation, 0 for real uploading.
3464 Returns 0 on failure, 1 on success.
3466 The 'local' argument is relative to the initial directory of the MPUT,
3467 i.e. the root of the tree being uploaded. If the directory of the
3468 argument file is different from the directory of the previous file
3469 (which is stored in global putpath[]), this routine does the appropriate
3470 CWDs, CDUPs, and/or MKDIRs to position the FTP server in the same place.
3472 static int cdlevel = 0, cdsimlvl = 0; /* Tree-level trackers */
3475 syncdir(local,sim) char * local; int sim; {
3476 char buf[CKMAXPATH+1];
3477 char tmp[CKMAXPATH+1];
3478 char msgbuf[CKMAXPATH+64];
3479 char c, * p = local, * s = buf, * q = buf, * psep, * ssep;
3480 int i, k = 0, done = 0, itsadir = 0, saveq;
3482 debug(F110,"ftp syncdir local (new)",local,0);
3483 debug(F110,"ftp syncdir putpath (old)",putpath,0);
3485 itsadir = isdir(local); /* Is the local file a directory? */
3488 while ((*s = *p)) { /* Copy the argument filename */
3489 if (++k == CKMAXPATH) /* so we can poke it. */
3491 if (*s == '/') /* Pointer to rightmost dirsep */
3496 if (!itsadir) /* If it's a regular file */
3497 *q = NUL; /* keep just the path part */
3499 debug(F110,"ftp syncdir buf",buf,0);
3500 if (!strcmp(buf,putpath)) { /* Same path as previous file? */
3501 if (itsadir) { /* This file is a directory? */
3502 if (doftpcwd(local,0)) { /* Try to CD to it */
3503 doftpcdup(); /* Worked - CD back up */
3504 } else if (sim) { /* Simulating... */
3505 if (fdispla == XYFD_B) {
3506 printf("WOULD CREATE DIRECTORY %s\n",local);
3507 } else if (fdispla) {
3508 ckmakmsg(msgbuf,CKMAXPATH,
3509 "WOULD CREATE DIRECTORY",local,NULL,NULL);
3510 ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,msgbuf);
3512 /* See note above */
3514 } else if (!doftpxmkd(local,0)) { /* Can't CD - try to create */
3516 } else { /* Remote directory created OK */
3517 if (fdispla == XYFD_B) {
3518 printf("CREATED DIRECTORY %s\n",local);
3519 } else if (fdispla) {
3520 ckmakmsg(msgbuf,CKMAXPATH+64,
3521 "CREATED DIRECTORY ",local,NULL,NULL);
3522 ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,msgbuf);
3526 debug(F110,"ftp syncdir no change",buf,0);
3527 return(1); /* Yes, done. */
3529 ckstrncpy(tmp,buf,CKMAXPATH+1); /* Make a safe (pre-poked) copy */
3530 debug(F110,"ftp syncdir new path",buf,0); /* for later (see end) */
3533 s = putpath; /* Old */
3535 debug(F110,"ftp syncdir A (old) s",s,0); /* Previous */
3536 debug(F110,"ftp syncdir A (new) p",p,0); /* New */
3540 while (*p != NUL && *s != NUL && *p == *s) {
3541 if (*p == '/') { psep = p+1; ssep = s+1; }
3545 psep and ssep point to the first path segment that differs.
3546 We have to do as many CDUPs as there are path segments in ssep.
3547 then we have to do as many MKDs and CWDs as there are segments in psep.
3552 debug(F110,"ftp syncdir B (old) s",s,0); /* Previous */
3553 debug(F110,"ftp syncdir B (new) p",p,0); /* New */
3555 /* p and s now point to the leftmost spot where the paths differ */
3557 if (*s) { /* We have to back up */
3558 k = 1; /* How many levels counting this one */
3559 while ((c = *s++)) { /* Count dirseps remaining in prev */
3563 debug(F101,"ftp syncdir levels up","",k);
3565 for (i = 1; i <= k; i++) { /* Do that many CDUPs */
3566 debug(F111,"ftp syncdir CDUP A",p,i);
3567 if (fdispla == XYFD_B)
3569 if (sim && cdsimlvl) {
3579 if (!*p) /* If we don't have to go down */
3580 goto xcwd; /* we're done. */
3583 while (p > buf && *p && *p != '/') /* If in middle of segment */
3584 p--; /* back up to beginning */
3585 if (*p == '/') /* and terminate there */
3587 #endif /* COMMENT */
3589 debug(F110,"ftp syncdir NEW PATH",p,0);
3591 s = p; /* Point to start of new down path. */
3592 while (1) { /* Loop through characters. */
3593 if (*s == '/' || !*s) { /* Have a segment. */
3594 if (!*s) /* If end of string, */
3595 done++; /* after this segment we're done. */
3597 *s = NUL; /* NUL out the separator. */
3598 if (*p) { /* If segment is not empty */
3599 debug(F110,"ftp syncdir down segment",p,0);
3600 if (!doftpcwd(p,0)) { /* Try to CD to it */
3602 if (fdispla == XYFD_B) {
3603 printf(" WOULD CREATE DIRECTORY %s\n",local);
3604 } else if (fdispla) {
3605 ckmakmsg(msgbuf,CKMAXPATH,
3606 "WOULD CREATE DIRECTORY",
3608 ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,msgbuf);
3612 if (!doftpxmkd(p,0)) { /* Can't CD - try to create */
3613 debug(F110,"ftp syncdir mkdir failed",p,0);
3615 Suppose we are executing SEND /RECURSIVE. Locally we have a directory
3616 FOO but the remote has a regular file with the same name. We can't CD
3617 to it, can't MKDIR it either. There's no way out but to fail and let
3618 the user handle the problem.
3623 debug(F110,"ftp syncdir mkdir OK",p,0);
3624 if (fdispla == XYFD_B) {
3625 printf(" CREATED DIRECTORY %s\n",p);
3626 } else if (fdispla) {
3627 ckmakmsg(msgbuf,CKMAXPATH,
3628 "CREATED DIRECTORY ",p,NULL,NULL);
3629 ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,msgbuf);
3631 if (!doftpcwd(p,0)) { /* Try again to CD */
3632 debug(F110,"ftp syncdir CD failed",p,0);
3636 if (fdispla == XYFD_B) printf(" CWD %s\n",p);
3637 debug(F110,"ftp syncdir CD OK",p,0);
3642 if (done) /* Quit if no next segment */
3644 p = s+1; /* Point to next segment */
3646 s++; /* Point to next source char */
3650 ckstrncpy(putpath,tmp,CKMAXPATH+1); /* All OK - make this the new path */
3658 dbtime(s,xx) char * s; struct tm * xx; { /* Write struct tm to debug log */
3660 debug(F111,"ftp year ",s,xx->tm_year);
3661 debug(F111,"ftp month",s,xx->tm_mon);
3662 debug(F111,"ftp day ",s,xx->tm_mday);
3663 debug(F111,"ftp hour ",s,xx->tm_hour);
3664 debug(F111,"ftp min ",s,xx->tm_min);
3665 debug(F111,"ftp sec ",s,xx->tm_sec);
3670 /* t m c o m p a r e -- Compare two struct tm's */
3672 /* Like strcmp() but for struct tm's */
3673 /* Returns -1 if xx < yy, 0 if they are equal, 1 if xx > yy */
3676 tmcompare(xx,yy) struct tm * xx, * yy; {
3678 if (xx->tm_year < yy->tm_year) /* First year less than second */
3680 if (xx->tm_year > yy->tm_year) /* First year greater than second */
3683 /* Years are equal so compare months */
3685 if (xx->tm_mon < yy->tm_mon) /* And so on... */
3687 if (xx->tm_mon > yy->tm_mon)
3690 if (xx->tm_mday < yy->tm_mday)
3692 if (xx->tm_mday > yy->tm_mday)
3695 if (xx->tm_hour < yy->tm_hour)
3697 if (xx->tm_hour > yy->tm_hour)
3700 if (xx->tm_min < yy->tm_min)
3702 if (xx->tm_min > yy->tm_min)
3705 if (xx->tm_sec < yy->tm_sec)
3707 if (xx->tm_sec > yy->tm_sec)
3712 #endif /* DOUPDATE */
3714 #ifndef HAVE_TIMEGM /* For platforms that do not have timegm() */
3715 static CONST int MONTHDAYS[] = { /* Number of days in each month. */
3716 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
3719 /* Macro for whether a given year is a leap year. */
3720 #define ISLEAP(year) \
3721 (((year) % 4) == 0 && (((year) % 100) != 0 || ((year) % 400) == 0))
3722 #endif /* HAVE_TIMEGM */
3724 /* m k u t i m e -- Like mktime() but argument is already UTC */
3728 mkutime(struct tm * tm)
3730 mkutime(tm) struct tm * tm;
3731 #endif /* CK_ANSIC */
3734 return(timegm(tm)); /* Have system service, use it. */
3737 Contributed by Russ Allbery (rra@stanford.edu), used by permission.
3738 Given a struct tm representing a calendar time in UTC, convert it to
3739 seconds since epoch. Returns (time_t) -1 if the time is not
3740 convertable. Note that this function does not canonicalize the provided
3741 struct tm, nor does it allow out-of-range values or years before 1970.
3742 Result should be identical with timegm().
3747 We do allow some ill-formed dates, but we don't do anything special
3748 with them and our callers really shouldn't pass them to us. Do
3749 explicitly disallow the ones that would cause invalid array accesses
3750 or other algorithm problems.
3754 debug(F101,"mkutime tm_mon","",tm->tm_mon);
3755 debug(F101,"mkutime tm_year","",tm->tm_year);
3758 if (tm->tm_mon < 0 || tm->tm_mon > 11 || tm->tm_year < 70)
3759 return((time_t) -1);
3761 /* Convert to time_t. */
3762 for (i = 1970; i < tm->tm_year + 1900; i++)
3763 result += 365 + ISLEAP(i);
3764 for (i = 0; i < tm->tm_mon; i++)
3765 result += MONTHDAYS[i];
3766 if (tm->tm_mon > 1 && ISLEAP(tm->tm_year + 1900))
3768 result = 24 * (result + tm->tm_mday - 1) + tm->tm_hour;
3769 result = 60 * result + tm->tm_min;
3770 result = 60 * result + tm->tm_sec;
3771 debug(F101,"mkutime result","",result);
3773 #endif /* HAVE_TIMEGM */
3778 s e t m o d t i m e -- Set file modification time.
3780 f = char * filename;
3781 t = time_t date/time to set (Secs since 19700101 0:00:00 UTC, NOT local)
3783 UNIX-specific; isolates mainline code from hideous #ifdefs.
3791 setmodtime(char * f, time_t t)
3793 setmodtime(f,t) char * f; time_t t;
3794 #endif /* CK_ANSIC */
3803 struct timeval tp[2];
3804 #else /* def BSD44 */
3816 #else /* def SYSUTIMEH */
3819 #define SYSUTIMEH /* Our utimbuf matches this one. */
3825 #endif /* def VMS [else] */
3826 #endif /* def SYSUTIMEH [else] */
3827 #endif /* def V7 [else] */
3828 #endif /* def BSD44 [else] */
3830 if (stat(f,&sb) < 0) {
3831 debug(F111,"setmodtime stat failure",f,errno);
3835 tp[0].tv_sec = sb.st_atime; /* Access time first */
3836 tp[1].tv_sec = t; /* Update time second */
3837 debug(F111,"setmodtime BSD44",f,t);
3840 tp.timep[0] = t; /* Set modif. time to creation date */
3841 tp.timep[1] = sb.st_atime; /* Don't change the access time */
3842 debug(F111,"setmodtime V7",f,t);
3845 tp.modtime = t; /* Set modif. time to creation date */
3846 tp.actime = sb.st_atime; /* Don't change the access time */
3847 debug(F111,"setmodtime SYSUTIMEH",f,t);
3849 tp.mtime = t; /* Set modif. time to creation date */
3850 tp.atime = sb.st_atime; /* Don't change the access time */
3851 debug(F111,"setmodtime (other)",f,t);
3852 #endif /* SYSUTIMEH */
3856 /* Try to set the file date */
3860 debug(F111,"setmodtime utimes()","BSD44",x);
3865 The following produces the nonsensical warning:
3866 Argument of type "const struct utimbuf *" is incompatible with
3867 parameter of type "const struct utimbuf *". If you can make it
3868 go away, be my guest.
3870 const struct utimbuf * t2 = &tp;
3875 debug(F111,"setmodtime utime()","other",x);
3881 debug(F101,"setmodtime result","",rc);
3887 c h k m o d t i m e -- Check/Set file modification time.
3892 0 if local older than remote,
3893 1 if modtimes are equal,
3894 2 if local newer than remote.
3895 1 = Set (local file's modtime from remote's); returns:
3900 chkmodtime(local,remote,fc) char * local, * remote; int fc; {
3902 struct _stat statbuf;
3904 struct stat statbuf;
3906 struct tm * tmlocal = NULL;
3908 int rc = 0, havedate = 0, lcs = -1, rcs = -1, flag = 0;
3909 char * s, timebuf[64];
3911 debug(F111,"chkmodtime",local,mdtmok);
3912 if (!mdtmok) /* Server supports MDTM? */
3913 return(-1); /* No don't bother. */
3918 if (lcs < 0) lcs = fcharset;
3920 if (rcs < 0) rcs = ftp_csr;
3922 #endif /* NOCSETS */
3925 rc = stat(local,&statbuf);
3926 if (rc == 0) { /* Get local file's mod time */
3927 /* Convert to struct tm */
3928 tmlocal = gmtime((time_t *)&statbuf.st_mtime);
3931 dbtime(local,tmlocal);
3936 /* Get remote file's mod time as yyyymmddhhmmss */
3938 if (havemdtm) { /* Already got it from MLSD? */
3941 } else if (ftpcmd("MDTM",remote,lcs,rcs,0) == REPLY_COMPLETE) {
3943 bzero((char *)&tmremote, sizeof(struct tm));
3945 while ((c = *s++)) { /* Skip past response code */
3953 debug(F111,"ftp chkmodtime string",s,flag);
3954 if (fts_sto) { /* User gave server time offset? */
3956 debug(F110,"ftp chkmodtime offset",fts_sto,0);
3957 ckmakmsg(timebuf,64,s," ",fts_sto,NULL); /* Build delta time */
3958 if ((p = cmcvtdate(timebuf,1))) { /* Apply delta time */
3959 ckstrncpy(timebuf,p,64); /* Convert to MDTM format */
3960 timebuf[8] = timebuf[9]; /* h */
3961 timebuf[9] = timebuf[10]; /* h */
3962 timebuf[10] = timebuf[12]; /* m */
3963 timebuf[11] = timebuf[13]; /* m */
3964 timebuf[12] = timebuf[12]; /* s */
3965 timebuf[13] = timebuf[13]; /* s */
3968 debug(F110,"ftp chkmodtime adjust",s,0);
3971 if (flag) { /* Convert to struct tm */
3973 int y2kbug = 0; /* Seen in Kerberos 4 FTP servers */
3974 if (!ckstrcmp(s,"191",3,0)) {
3975 pat = "%05d%02d%02d%02d%02d%02d";
3977 debug(F110,"ftp chkmodtime Y2K BUG detected",s,0);
3979 pat = "%04d%02d%02d%02d%02d%02d";
3981 if (sscanf(s, /* Parse into struct tm */
3983 &(tmremote.tm_year),
3985 &(tmremote.tm_mday),
3986 &(tmremote.tm_hour),
3990 tmremote.tm_year -= (y2kbug ? 19000 : 1900);
3991 debug(F101,"ftp chkmodtime year","",tmremote.tm_year);
3995 debug(F100,"SERVER TIME FOLLOWS:","",0);
3996 dbtime(remote,&tmremote);
4003 } else { /* Failed */
4004 debug(F101,"ftp chkmodtime ftpcode","",ftpcode);
4005 if (ftpcode == 500 || /* Command unrecognized */
4006 ftpcode == 502 || /* Command not implemented */
4007 ftpcode == 202) /* Command superfluous */
4008 mdtmok = 0; /* Don't ask this server again */
4011 if (fc == 0) { /* Compare */
4012 if (havedate == 1) { /* Only if we have both file dates */
4014 Compare with local file's time. We don't use
4015 clock time (time_t) here in case of signed/unsigned
4022 dbtime("LOCAL",tmlocal);
4023 dbtime("REMOT",&tmremote);
4026 #endif /* COMMENT */
4027 xx = tmcompare(tmlocal,&tmremote);
4028 debug(F101,"chkmodtime tmcompare","",xx);
4031 } else if (ftp_dates) { /* Set */
4033 Here we must convert struct tm to time_t
4034 without applying timezone conversion, for which
4035 there is no portable API. The method is hidden
4036 in mkutime(), defined above.
4039 utc = mkutime(&tmremote);
4040 debug(F111,"ftp chkmodtime mkutime",remote,utc);
4041 if (utc != (time_t)-1)
4042 return(setmodtime(local,utc));
4047 /* getfile() returns: -1 on error, 0 if file received, 1 if file skipped */
4050 getfile(remote,local,recover,append,pipename,xlate,fcs,rcs)
4051 char * local, * remote, * pipename; int recover, append, xlate, fcs, rcs;
4060 #endif /* GFTIMER */
4061 char fullname[CKMAXPATH+1];
4063 debug(F110,"ftp getfile remote A",remote,0);
4064 debug(F110,"ftp getfile local A",local,0);
4065 debug(F110,"ftp getfile pipename",pipename,0);
4066 if (!remote) remote = "";
4069 /* Automatic type switching? */
4070 if (ftp_xfermode == XMODE_A && patterns && get_auto && !forcetype) {
4072 x = matchname(remote,0,servertype);
4073 debug(F111,"ftp getfile matchname",remote,x);
4075 case 0: ftp_typ = FTT_ASC; break;
4076 case 1: ftp_typ = tenex ? FTT_TEN : FTT_BIN; break;
4077 default: if (g_ftp_typ > -1) ftp_typ = g_ftp_typ;
4079 changetype(ftp_typ,ftp_vbm);
4080 binary = ftp_typ; /* For file-transfer display */
4082 #endif /* PATTERNS */
4085 ftp_csx = -1; /* For file-transfer display */
4086 ftp_csl = -1; /* ... */
4088 if (rcs > -1) /* -1 means no translation */
4089 if (ftp_typ == FTT_ASC) /* File type is "ascii"? */
4090 if (fcs < 0) /* File charset not forced? */
4091 fcs = fcharset; /* use prevailing FILE CHARACTER-SET */
4092 if (fcs > -1 && rcs > -1) { /* Set up translation functions */
4093 debug(F110,"ftp getfile","initxlate",0);
4094 initxlate(rcs,fcs); /* NB: opposite order of PUT */
4099 #endif /* NOCSETS */
4101 if (!local) local = "";
4102 if (!pipename && !*local)
4105 out2screen = !strcmp(local,"-");
4109 ckstrncpy(fullname,pipename,CKMAXPATH+1);
4111 zfnqfp(local,CKMAXPATH,fullname);
4113 ckstrncpy(fullname,local,CKMAXPATH+1);
4115 if (!out2screen && displa && fdispla) { /* Screen */
4116 ftscreen(SCR_FN,'F',(CK_OFF_T)pktnum,remote);
4117 ftscreen(SCR_AN,0,(CK_OFF_T)0,fullname);
4118 ftscreen(SCR_FS,0,fsize,"");
4120 tlog(F110,ftp_typ ? "ftp get BINARY:" : "ftp get TEXT:", remote, 0);
4121 tlog(F110," as",fullname,0);
4122 debug(F111,"ftp getfile size",remote,fsize);
4123 debug(F111,"ftp getfile local",local,out2screen);
4125 ckstrncpy(filnam, pipename ? remote : local, CKMAXPATH);
4127 t0 = gmstimer(); /* Start time */
4128 debug(F111,"ftp getfile t0",remote,t0); /* ^^^ */
4129 rc = recvrequest("RETR",
4132 append ? "ab" : "wb",
4140 t1 = gmstimer(); /* End time */
4141 debug(F111,"ftp getfile t1",remote,t1);
4142 debug(F111,"ftp getfile sec",remote,(t1-t0)/1000);
4144 sec = (CKFLOAT)((CKFLOAT)(t1 - t0) / 1000.0); /* Stats */
4145 fpxfsecs = sec; /* (for doxlog()) */
4147 sec = (t1 - t0) / 1000;
4149 #endif /* GFTIMER */
4154 #endif /* FTP_TIMEOUT */
4156 debug(F111,"ftp recvrequest rc",remote,rc);
4157 if (cancelfile || cancelgroup) {
4158 debug(F111,"ftp get canceled",ckitoa(cancelfile),cancelgroup);
4159 ftscreen(SCR_ST,ST_INT,(CK_OFF_T)0,"");
4160 } else if (rc > 0) {
4161 debug(F111,"ftp get skipped",ckitoa(cancelfile),cancelgroup);
4162 ftscreen(SCR_ST,ST_SKIP,(CK_OFF_T)0,cmarg);
4163 } else if (rc < 0) {
4165 case -4: /* Network error */
4166 case -2: /* File error */
4167 ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,ck_errstr());
4170 ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,
4171 "Failure to make data connection");
4173 case -1: /* (should be covered above) */
4174 ftscreen(SCR_ST,ST_INT,(CK_OFF_T)0,"");
4177 ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,&ftp_reply_str[4]);
4179 } else { /* Tudo bem */
4180 ftscreen(SCR_PT,'Z',(CK_OFF_T)0,"");
4182 ftscreen(SCR_ST,ST_OK,(CK_OFF_T)0,""); /* For screen */
4183 makestr(&rrfspec,remote); /* For WHERE command */
4184 makestr(&rfspec,fullname);
4188 if (ftp_dates) /* If FTP DATES ON... */
4189 if (!pipename && !out2screen) /* and it's a real file */
4190 if (rc < 1 && rc != -3) /* and it wasn't skipped */
4191 if (connected) /* and we still have a connection */
4192 if (zchki(local) > -1) { /* and the file wasn't discarded */
4193 chkmodtime(local,remote,1); /* set local file date */
4194 debug(F110,"ftp get set date",local,0);
4196 filcnt++; /* Used by \v(filenum) */
4201 tlog(F100," recovery skipped","",0);
4202 } else if (rc == 0) {
4203 tlog(F101," complete, size", "", fsize);
4204 } else if (cancelfile) {
4205 tlog(F100," canceled by user","",0);
4207 } else if (ftp_timed_out) {
4208 tlog(F100," timed out","",0);
4209 #endif /* FTP_TIMEOUT */
4211 tlog(F110," failed:",ftp_reply_str,0);
4214 doxlog(what,local,fsize,ftp_typ,rc,"");
4220 /* putfile() returns: -1 on error, >0 if file not selected, 0 on success. */
4221 /* Positive return value is Skip Reason, SKP_xxx, from ckcker.h. */
4225 local,remote,force,moving,mvto,rnto,srvrn,x_cnv,x_usn,xft,prm,fcs,rcs,flg)
4226 char * local, * remote, * mvto, *rnto, *srvrn;
4227 int cx, force, moving, x_cnv, x_usn, xft, fcs, rcs, flg, prm;
4231 char asname[CKMAXPATH+1];
4232 char fullname[CKMAXPATH+1];
4233 int k = -1, x = 0, y = 0, o = -1, rc = 0, nc = 0;
4234 int xlate = 0, restart = 0, mt = -1;
4235 char * s = NULL, * cmd = NULL;
4236 ULONG t0 = 0, t1 = 0; /* Times for stats */
4237 int ofcs = 0, orcs = 0;
4243 #endif /* GFTIMER */
4244 debug(F111,"ftp putfile flg",local,flg);
4245 debug(F110,"ftp putfile srv_renam",srvrn,0);
4246 debug(F101,"ftp putfile fcs","",fcs);
4247 debug(F101,"ftp putfile rcs","",rcs);
4249 ofcs = fcs; /* Save charset args */
4252 sendstart = (CK_OFF_T)0;
4253 restart = flg & PUT_RES;
4257 /* FTP protocol command to send to server */
4258 cmd = (cx == FTP_APP) ? "APPE" : (x_usn ? "STOU" : "STOR");
4260 if (x_cnv == SET_AUTO) { /* Name conversion is auto */
4261 if (alike) { /* If server & client are alike */
4262 nc = 0; /* no conversion */
4263 } else { /* If they are different */
4264 if (servertype == SYS_UNIX || servertype == SYS_WIN32)
4265 nc = -1; /* only minimal conversions needed */
4266 else /* otherwise */
4267 nc = 1; /* full conversion */
4269 } else /* Not auto - do what user said */
4272 /* If Transfer Mode is Automatic, determine file type */
4273 if (ftp_xfermode == XMODE_A && filepeek && !pipesend) {
4274 if (isdir(local)) { /* If it's a directory */
4275 k = FT_BIN; /* skip the file scan */
4277 debug(F110,"FTP PUT calling scanfile",local,0);
4278 k = scanfile(local,&o,nscanfile); /* Scan the file */
4280 debug(F111,"FTP PUT scanfile",local,k);
4281 if (k > -1 && !forcetype) {
4282 ftp_typ = (k == FT_BIN) ? 1 : 0;
4283 if (xft > -1 && ftp_typ != xft) {
4285 tlog(F110,"ftp put SKIP (Type):", local, 0);
4288 if (ftp_typ == 1 && tenex) /* User said TENEX? */
4293 ftp_csx = -1; /* For file-transfer display */
4294 ftp_csl = -1; /* ... */
4296 if (rcs > -1) { /* -1 means no translation */
4297 if (ftp_typ == 0) { /* File type is "ascii"? */
4298 if (fcs < 0) { /* File charset not forced? */
4299 if (k < 0) { /* If we didn't scan */
4300 fcs = fcharset; /* use prevailing FILE CHARACTER-SET */
4301 } else { /* If we did scan, use scan result */
4303 case FT_TEXT: /* Unknown text */
4306 case FT_7BIT: /* 7-bit text */
4309 case FT_8BIT: /* 8-bit text */
4312 case FT_UTF8: /* UTF-8 */
4315 case FT_UCS2: /* UCS-2 */
4317 if (o > -1) /* Input file byte order */
4327 if (fcs > -1 && rcs > -1) { /* Set up translation functions */
4328 debug(F110,"ftp putfile","initxlate",0);
4330 debug(F111,"ftp putfile rcs",fcsinfo[rcs].keyword,rcs);
4335 #endif /* NOCSETS */
4337 binary = ftp_typ; /* For file-transfer display */
4340 if (recursive) { /* If sending recursively, */
4341 if (!syncdir(local,flg & PUT_SIM)) /* synchronize directories. */
4342 return(-1); /* Don't PUT if it fails. */
4343 else if (isdir(local)) /* It's a directory */
4344 return(0); /* Don't send it! */
4346 if (*remote) { /* If an as-name template was given */
4348 if (cmd_quoting) { /* and COMMAND QUOTING is ON */
4349 y = CKMAXPATH; /* evaluate it for this file */
4351 zzstring(remote,&s,&y);
4354 ckstrncpy(asname,remote,CKMAXPATH); /* (or take it literally) */
4355 } else { /* No as-name */
4356 nzltor(local,asname,nc,0,CKMAXPATH); /* use local name strip path */
4357 debug(F110,"FTP PUT nzltor",asname,0);
4359 /* Preliminary messages and log entries */
4362 zfnqfp(local,CKMAXPATH,fullname);
4363 if (!fullname[0]) ckstrncpy(fullname,local,CKMAXPATH+1);
4364 fullname[CKMAXPATH] = NUL;
4366 if (displa && fdispla) { /* Screen */
4367 ftscreen(SCR_FN,'F',(CK_OFF_T)pktnum,local);
4368 ftscreen(SCR_AN,0,(CK_OFF_T)0,asname);
4369 ftscreen(SCR_FS,0,fsize,"");
4372 if (flg & (PUT_UPD|PUT_DIF)) { /* Date-checking modes... */
4373 mt = chkmodtime(fullname,asname,0);
4374 debug(F111,"ftp putfile chkmodtime",asname,mt);
4375 if (mt == 0 && ((flg & PUT_DIF) == 0)) { /* Local is older */
4376 tlog(F110,"ftp put /update SKIP (Older modtime): ",fullname,0);
4378 ftscreen(SCR_ST,ST_SKIP,(CK_OFF_T)SKP_DAT,fullname);
4381 } else if (mt == 1) { /* Times are equal */
4382 tlog(F110,"ftp put /update SKIP (Equal modtime): ",fullname,0);
4383 ftscreen(SCR_ST,ST_SKIP,(CK_OFF_T)SKP_EQU,fullname); /* Skip it */
4387 /* Local file is newer */
4388 tlog(F110,ftp_typ ? "ftp put /update BINARY:" :
4389 "ftp put /update TEXT:", fullname, 0);
4390 } else if (flg & PUT_RES) {
4391 tlog(F110,ftp_typ ? "ftp put /recover BINARY:" :
4392 "ftp put /recover TEXT:", fullname, 0);
4394 tlog(F110,ftp_typ ? "ftp put BINARY:" : "ftp put TEXT:", fullname, 0);
4397 tlog(F110,ftp_typ ? "ftp put BINARY:" : "ftp put TEXT:", fullname, 0);
4398 #endif /* DOUPDATE */
4399 tlog(F110," as",asname,0);
4403 debug(F111,"ftp putfile fcs",fcsinfo[fcs].keyword,fcs);
4404 tlog(F110," file character set:",fcsinfo[fcs].keyword,0);
4405 tlog(F110," server character set:",fcsinfo[rcs].keyword,0);
4406 } else if (!ftp_typ) {
4407 tlog(F110," character sets:","no conversion",0);
4408 fcs = ofcs; /* Binary file but we still must */
4409 rcs = orcs; /* translate its name */
4411 #endif /* NOCSETS */
4415 t0 = gmstimer(); /* Start time */
4416 if (flg & PUT_SIM) { /* rc > 0 is a skip reason code */
4417 if (flg & (PUT_UPD|PUT_DIF)) { /* (see SKP_xxx in ckcker.h) */
4418 rc = (mt < 0) ? /* Update mode... */
4419 SKP_XNX : /* Remote file doesn't exist */
4420 SKP_XUP; /* Remote file is older */
4422 rc = SKP_SIM; /* "Would be sent", period. */
4425 rc = sendrequest(cmd,local,asname,xlate,fcs,rcs,restart);
4427 t1 = gmstimer(); /* End time */
4428 filcnt++; /* File number */
4431 sec = (CKFLOAT)((CKFLOAT)(t1 - t0) / 1000.0); /* Stats */
4432 fpxfsecs = sec; /* (for doxlog()) */
4434 sec = (t1 - t0) / 1000;
4436 #endif /* GFTIMER */
4438 debug(F111,"ftp sendrequest rc",local,rc);
4440 if (cancelfile || cancelgroup) {
4441 debug(F111,"ftp put canceled",ckitoa(cancelfile),cancelgroup);
4442 ftscreen(SCR_ST,ST_INT,(CK_OFF_T)0,"");
4443 } else if (rc > 0) {
4444 debug(F101,"ftp put skipped",local,rc);
4445 ftscreen(SCR_ST,ST_SKIP,(CK_OFF_T)rc,fullname);
4446 } else if (rc < 0) {
4447 debug(F111,"ftp put error",local,ftpcode);
4448 ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,&ftp_reply_str[4]);
4450 debug(F111,"ftp put not canceled",ckitoa(displa),fdispla);
4451 ftscreen(SCR_PT,'Z',(CK_OFF_T)0,"");
4452 debug(F111,"ftp put ST_OK",local,rc);
4453 ftscreen(SCR_ST,ST_OK,(CK_OFF_T)0,"");
4454 debug(F110,"ftp put old sfspec",sfspec,0);
4455 makestr(&sfspec,fullname); /* For WHERE command */
4456 debug(F110,"ftp put new sfspec",sfspec,0);
4457 debug(F110,"ftp put old srfspec",srfspec,0);
4458 makestr(&srfspec,asname);
4459 debug(F110,"ftp put new srfspec",srfspec,0);
4462 /* Final log entries */
4468 tlog(F100," /simulate: WOULD BE SENT:","no remote file",0);
4469 else if (rc == SKP_XUP)
4470 tlog(F100," /simulate: WOULD BE SENT:","remote file older",0);
4471 else if (rc == SKP_SIM)
4472 tlog(F100," /simulate: WOULD BE SENT","",0);
4474 tlog(F110," skipped:",gskreason(rc),0);
4475 } else if (rc == 0) {
4476 tlog(F101," complete, size", "", fsize);
4477 } else if (cancelfile) {
4478 tlog(F100," canceled by user","",0);
4480 tlog(F110," failed:",ftp_reply_str,0);
4483 doxlog(what,local,fsize,ftp_typ,rc,"");
4487 if (rc < 0) /* PUT did not succeed */
4488 return(-1); /* so done. */
4490 if (flg & PUT_SIM) /* Simulating, skip the rest. */
4494 /* Set permissions too? */
4496 if (prm) { /* Change permissions? */
4497 s = zgperm(local); /* Get perms of local file */
4500 if (x > 3) s += (x - 3);
4502 ckmakmsg(ftpcmdbuf,FTP_BUFSIZ,s," ",asname,NULL);
4504 ftpcmd("SITE CHMOD",ftpcmdbuf,fcs,rcs,ftp_vbm) == REPLY_COMPLETE;
4505 tlog(F110, x ? " chmod" : " chmod failed",
4515 /* Disposition of source file */
4519 tlog(F110, (x > -1) ?
4520 " deleted" : " failed to delete",
4527 x = zrename(local,mvto);
4528 tlog(F110, (x > -1) ?
4529 " moved source to" : " failed to move source to",
4535 /* ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,mvto); */
4540 int y; /* Pass it thru the evaluator */
4541 extern int cmd_quoting; /* for \v(filename) */
4542 if (cmd_quoting) { /* But only if cmd_quoting is on */
4545 zzstring(rnto,&s,&y);
4551 x = zrename(local,s);
4552 tlog(F110, (x > -1) ?
4553 " renamed source file to" :
4554 " failed to rename source file to",
4560 /* ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,s); */
4564 /* Disposition of destination file */
4566 if (srvrn) { /* /SERVER-RENAME: */
4569 int y; /* Pass it thru the evaluator */
4570 extern int cmd_quoting; /* for \v(filename) */
4571 debug(F111,"ftp putfile srvrn",s,1);
4573 if (cmd_quoting) { /* But only if cmd_quoting is on */
4575 s = (char *)fullname; /* We can recycle this buffer now */
4576 zzstring(srvrn,&s,&y);
4577 s = (char *)fullname;
4580 debug(F111,"ftp putfile srvrn",s,2);
4583 x = ftp_rename(asname,s);
4584 debug(F111,"ftp putfile ftp_rename",asname,x);
4585 tlog(F110, (x > 0) ?
4586 " renamed destination file to" :
4587 " failed to rename destination file to",
4598 /* xxout must only be used for ASCII transfers */
4604 #endif /* CK_ANSIC */
4610 /* For Unix, DG, Stratus, Amiga, Gemdos, other */
4612 if (zzout(dout,(CHAR)'\015') < 0)
4619 if (zzout(dout,(CHAR)'\015') < 0)
4627 if (zzout(dout,(CHAR)'\015') < 0)
4634 if (zzout(dout,(CHAR)c) < 0)
4645 #endif /* CK_ANSIC */
4655 #endif /* CK_ANSIC */
4661 ispathsep(c) int c; {
4662 switch (servertype) {
4666 return(((c == ']') || (c == '>') || (c == ':')) ? 1 : 0);
4670 return(((c == '\\') || (c == '/') || (c == ':')) ? 1 : 0);
4672 return((c == '>') ? 1 : 0);
4674 return((c == '/') ? 1 : 0);
4681 extern int ck_repaint();
4682 #endif /* CK_CURSES */
4687 x = conchk(); /* Any chars waiting at console? */
4688 if (x-- > 0) { /* Yes... */
4689 c = coninc(5); /* Get one */
4691 case 032: /* Ctrl-X or X */
4693 case 'Z': cancelgroup++; /* fall thru on purpose */
4694 case 030: /* Ctrl-Z or Z */
4696 case 'X': cancelfile++; rc++; break;
4700 case 014: /* Ctrl-L or L or Ctrl-W */
4702 ck_repaint(); /* Refresh screen */
4703 #endif /* CK_CURSES */
4706 while (x-- > 0) /* Soak up any rest */
4712 /* fc = 0 for read; 1 for write */
4714 check_data_connection(fd,fc) int fd, fc; {
4717 fd_set in, out, err;
4719 if (ftp_timeout < 1L)
4725 FD_SET(fd,fc ? &out : &in);
4726 tv.tv_sec = ftp_timeout; /* Time limit */
4730 x = select(FD_SETSIZE,(int *)&in,(int *)&out,(int *)&err,&tv);
4732 x = select(FD_SETSIZE,&in,&out,&err,&tv);
4733 #endif /* INTSELECT */
4737 errno = EWOULDBLOCK;
4744 #endif /* EWOULDBLOCK */
4745 debug(F100,"ftp check_data_connection TIMOUT","",0);
4750 #endif /* FTP_TIMEOUT */
4752 /* zzsend - used by buffered output macros. */
4756 zzsend(int fd, CHAR c)
4758 zzsend(fd,c) int fd; CHAR c;
4759 #endif /* CK_ANSIC */
4763 debug(F101,"zzsend ucbufsiz","",ucbufsiz);
4764 debug(F101,"zzsend nout","",nout);
4765 debug(F111,"zzsend","secure?",ftpissecure());
4767 if (iscanceled()) /* Check for cancellation */
4772 if (check_data_connection(fd,1) < 0) {
4776 #endif /* FTP_TIMEOUT */
4778 rc = (!ftpissecure()) ?
4779 send(fd, (SENDARG2TYPE)ucbuf, nout, 0) :
4780 secure_putbuf(fd, ucbuf, nout);
4786 if (rc > -1 && fdispla != XYFD_B) {
4788 ftscreen(SCR_PT,'D',(CK_OFF_T)spackets,NULL);
4793 /* c m d l i n p u t -- Command-line PUT */
4796 cmdlinput(stay) int stay; {
4797 int x, rc = 0, done = 0, good = 0, status = 0;
4798 ULONG t0, t1; /* Times for stats */
4803 #endif /* GFTIMER */
4805 if (quiet) { /* -q really means quiet */
4815 what = W_FTP|W_SEND;
4822 t0 = gmstimer(); /* Record starting time */
4824 while (!done && !cancelgroup) { /* Loop for all files */
4827 x = gnfile(); /* Get next file from list(s) */
4828 if (x == 0) /* (see gnfile() comments...) */
4832 case 1: /* File to send */
4833 rc = putfile(FTP_PUT, /* Function (PUT, APPEND) */
4834 filnam, /* Local file to send */
4835 filnam, /* Remote name for file */
4836 forcetype, /* Text/binary mode forced */
4838 NULL, /* No move-to */
4839 NULL, /* No rename-to */
4840 NULL, /* No server-rename */
4841 ftp_cnv, /* Filename conversion */
4842 0, /* Unique-server-names */
4843 -1, /* All file types */
4844 0, /* No permissions */
4845 -1, /* No character sets */
4846 -1, /* No character sets */
4847 0 /* No update or restart */
4854 continue; /* Or break? */
4859 continue; /* Or break? */
4861 case 0: /* No more files, done */
4867 printf("?%s: file not found - \"%s\"\n",
4868 puterror ? "Fatal" : "Warning",
4871 continue; /* or break? */
4873 printf("?Warning access denied - \"%s\"\n", filnam);
4874 continue; /* or break? */
4876 printf("?Too many files match\n");
4881 printf("?No files selected\n");
4885 printf("?getnextfile() - unknown failure\n");
4892 else if (cancelfile && good < 1)
4898 lastxfer = W_FTP|W_SEND;
4901 t1 = gmstimer(); /* End time */
4903 sec = (CKFLOAT)((CKFLOAT)(t1 - t0) / 1000.0); /* Stats */
4904 if (!sec) sec = 0.001;
4907 sec = (t1 - t0) / 1000;
4909 #endif /* GFTIMER */
4910 tfcps = (long) (tfc / sec);
4912 lastxfer = W_FTP|W_SEND;
4915 ftscreen(status > 0 ? SCR_TC : SCR_CW, 0, (CK_OFF_T)0, "");
4917 doexit(success ? GOOD_EXIT : BAD_EXIT, -1);
4922 /* d o f t p p u t -- Parse and execute PUT, MPUT, and APPEND */
4926 doftpput(int cx, int who) /* who == 1 for ftp, 0 for kermit */
4928 doftpput(cx,who) int cx, who;
4929 #endif /* CK_ANSIC */
4931 struct FDB sf, fl, sw, cm;
4932 int n, rc, confirmed = 0, wild = 0, getval = 0, mput = 0, done = 0;
4933 int x_cnv = 0, x_usn = 0, x_prm = 0, putflags = 0, status = 0, good = 0;
4936 int x_csl, x_csr = -1; /* Local and remote charsets */
4939 char c, * p; /* Workers */
4941 int range[2]; /* Array range */
4942 char ** ap = NULL; /* Array pointer */
4943 int arrayx = -1; /* Array index */
4944 #endif /* PUTARRAY */
4945 ULONG t0 = 0L, t1 = 0L; /* Times for stats */
4950 #endif /* GFTIMER */
4952 struct stringint pv[SND_MAX+1]; /* Temporary array for switch values */
4953 success = 0; /* Assume failure */
4954 forcetype = 0; /* No /TEXT or /BINARY given yet */
4955 out2screen = 0; /* Not outputting file to screen */
4956 putflags = 0; /* PUT options */
4957 x_cnv = ftp_cnv; /* Filename conversion */
4958 x_usn = ftp_usn; /* Unique server names */
4959 x_prm = ftp_prm; /* Permissions */
4960 if (x_prm == SET_AUTO) /* Permissions AUTO */
4964 x_csr = ftp_csr; /* Inherit global server charset */
4969 #endif /* NOCSETS */
4971 makestr(&filefile,NULL); /* No filename list file yet. */
4972 makestr(&srv_renam,NULL); /* Clear /SERVER-RENAME: */
4973 makestr(&snd_rename,NULL); /* PUT /RENAME */
4974 makestr(&snd_move,NULL); /* PUT /MOVE */
4975 putpath[0] = NUL; /* Initialize for syncdir(). */
4976 puterror = ftp_err; /* Inherit global error action. */
4977 what = W_SEND|W_FTP; /* What we're doing (sending w/FTP) */
4978 asnambuf[0] = NUL; /* Clear as-name buffer */
4980 if (g_ftp_typ > -1) { /* Restore TYPE if saved */
4981 ftp_typ = g_ftp_typ;
4982 /* g_ftp_typ = -1; */
4984 for (i = 0; i <= SND_MAX; i++) { /* Initialize switch values */
4985 pv[i].sval = NULL; /* to null pointers */
4986 pv[i].ival = -1; /* and -1 int values */
4987 pv[i].wval = (CK_OFF_T)-1; /* and -1 wide values */
4989 if (who == 0) { /* Called with unprefixed command */
4991 case XXRSEN: pv[SND_RES].ival = 1; break;
4992 case XXCSEN: pv[SND_CMD].ival = 1; break;
4993 case XXMOVE: pv[SND_DEL].ival = 1; break;
4994 case XXMMOVE: pv[SND_DEL].ival = 1; /* fall thru */
4995 case XXMSE: mput++; break;
4999 pv[SND_RES].ival = 1;
5003 cmfdbi(&sw, /* First FDB - command switches */
5005 "Filename, or switch", /* hlpmsg */
5007 "", /* addtl string data */
5008 nputswi, /* addtl numeric data 1: tbl size */
5009 4, /* addtl numeric data 2: 4 = cmswi */
5010 xxstring, /* Processing function */
5011 putswi, /* Keyword table */
5012 &sf /* Pointer to next FDB */
5014 cmfdbi(&fl, /* 3rd FDB - local filespec */
5018 "", /* addtl string data */
5019 0, /* addtl numeric data 1 */
5020 0, /* addtl numeric data 2 */
5025 cmfdbi(&cm, /* 4th FDB - Confirmation */
5029 "", /* addtl string data */
5030 0, /* addtl numeric data 1 */
5031 0, /* addtl numeric data 2 */
5038 cmfdbi(&sf, /* 2nd FDB - file to send */
5042 "", /* addtl string data */
5043 /* 0 = parse files, 1 = parse files or dirs, 2 = skip symlinks */
5044 nolinks | x_recurse, /* addtl numeric data 1 */
5045 0, /* dirflg 0 means "not dirs only" */
5052 #endif /* COMMENT */
5055 while (1) { /* Parse zero or more switches */
5056 x = cmfdb(&sw); /* Parse something */
5057 debug(F101,"ftp put cmfdb A","",x);
5058 debug(F101,"ftp put fcode A","",cmresult.fcode);
5059 if (x < 0) /* Error */
5060 goto xputx; /* or reparse needed */
5061 if (cmresult.fcode != _CMKEY) /* Break out of loop if not a switch */
5063 c = cmgbrk(); /* Get break character */
5064 getval = (c == ':' || c == '='); /* to see how they ended the switch */
5065 if (getval && !(cmresult.kflags & CM_ARG)) {
5066 printf("?This switch does not take arguments\n");
5070 if (!getval && (cmgkwflgs() & CM_ARG)) {
5071 printf("?This switch requires an argument\n");
5075 n = cmresult.nresult; /* Numeric result = switch value */
5076 debug(F101,"ftp put switch","",n);
5078 switch (n) { /* Process the switch */
5079 case SND_AFT: /* Send /AFTER:date-time */
5080 case SND_BEF: /* Send /BEFORE:date-time */
5081 case SND_NAF: /* Send /NOT-AFTER:date-time */
5082 case SND_NBE: /* Send /NOT-BEFORE:date-time */
5084 if ((x = cmdate("File date-time","",&s,0,xxstring)) < 0) {
5086 printf("?Date-time required\n");
5092 makestr(&(pv[n].sval),s);
5095 case SND_ASN: /* /AS-NAME: */
5096 debug(F101,"ftp put /as-name getval","",getval);
5098 if ((x = cmfld("Name to send under","",&s,NULL)) < 0) {
5100 printf("?name required\n");
5105 makestr(&(pv[n].sval),brstrip(s));
5106 debug(F110,"ftp put /as-name 1",pv[n].sval,0);
5107 if (pv[n].sval) pv[n].ival = 1;
5111 case SND_ARR: /* /ARRAY */
5114 if ((x = cmfld("Array name (a single letter will do)",
5124 if ((x = arraybounds(s,&(range[0]),&(range[1]))) < 0) {
5125 printf("?Bad array: %s\n",s);
5128 if (!(ap = a_ptr[x])) {
5129 printf("?No such array: %s\n",s);
5133 pv[SND_CMD].ival = 0; /* Undo any conflicting ones... */
5134 pv[SND_RES].ival = 0;
5135 pv[SND_FIL].ival = 0;
5138 #endif /* PUTARRAY */
5140 case SND_BIN: /* /BINARY */
5141 case SND_TXT: /* /TEXT or /ASCII */
5142 case SND_TEN: /* /TENEX */
5143 pv[SND_BIN].ival = 0;
5144 pv[SND_TXT].ival = 0;
5145 pv[SND_TEN].ival = 0;
5150 case SND_CMD: /* These take no args */
5152 printf("?Sorry, system command access is disabled\n");
5157 else if (sndfilter) {
5158 printf("?Sorry, no PUT /COMMAND when SEND FILTER selected\n");
5162 #endif /* PIPESEND */
5163 sw.hlpmsg = "Command, or switch"; /* Change help message */
5164 pv[n].ival = 1; /* Just set the flag */
5165 pv[SND_ARR].ival = 0;
5167 #endif /* PUTPIPE */
5172 goto again; /* Because CMIFI params changed... */
5176 #endif /* CKSYMLINK */
5179 case SND_RES: /* /RECOVER (resend) */
5180 pv[SND_ARR].ival = 0; /* fall thru on purpose... */
5181 #endif /* FTP_RESTART */
5184 case SND_DEL: /* /DELETE */
5185 case SND_SHH: /* /QUIET */
5186 case SND_UPD: /* /UPDATE */
5187 case SND_SIM: /* /UPDATE */
5188 case SND_USN: /* /UNIQUE */
5189 pv[n].ival = 1; /* Just set the flag */
5192 case SND_REC: /* /RECURSIVE */
5193 recursive = 2; /* Must be set before cmifi() */
5195 goto again; /* Because CMIFI params changed... */
5199 case SND_DOT: /* /DOTFILES */
5202 case SND_NOD: /* /NODOTFILES */
5205 #endif /* UNIXOROSK */
5207 case SND_ERR: /* /ERROR-ACTION */
5208 if ((x = cmkey(qorp,2,"","",xxstring)) < 0)
5213 case SND_EXC: /* Excludes */
5215 if ((x = cmfld("Pattern","",&s,xxstring)) < 0) {
5217 printf("?Pattern required\n");
5222 if (s) if (!*s) s = NULL;
5223 makestr(&(pv[n].sval),s);
5228 case SND_PRM: /* /PERMISSIONS */
5231 else if ((x = cmkey(onoff,2,"","on",xxstring)) < 0)
5233 pv[SND_PRM].ival = x;
5237 case SND_FLT: /* /FILTER */
5238 debug(F101,"ftp put /filter getval","",getval);
5240 if ((x = cmfld("Filter program to send through","",&s,NULL)) < 0) {
5246 if (*s) s = brstrip(s);
5248 for (x = 0; x < y; x++) { /* Make sure they included "\v(...)" */
5249 if (s[x] != '\\') continue;
5250 if (s[x+1] == 'v') break;
5254 "?Filter must contain a replacement variable for filename.\n"
5259 if (s) if (!*s) s = NULL;
5260 makestr(&(pv[n].sval),s);
5264 #endif /* PIPESEND */
5266 case SND_NAM: /* /FILENAMES */
5268 if ((x = cmkey(fntab,nfntab,"","automatic",xxstring)) < 0)
5270 debug(F101,"ftp put /filenames","",x);
5274 case SND_SMA: /* Smaller / larger than */
5278 if ((x = cmnumw("Size in bytes","0",10,&y,xxstring)) < 0)
5283 case SND_FIL: /* Name of file containing filenames */
5285 if ((x = cmifi("Name of file containing list of filenames",
5286 "",&s,&y,xxstring)) < 0) {
5288 printf("?Filename required\n");
5292 } else if (y && iswild(s)) {
5293 printf("?Wildcards not allowed\n");
5297 if (s) if (!*s) s = NULL;
5298 makestr(&(pv[n].sval),s);
5301 pv[SND_ARR].ival = 0;
5308 case SND_MOV: /* MOVE after */
5309 case SND_REN: /* RENAME after */
5310 case SND_SRN: { /* SERVER-RENAME after */
5314 m = "device and/or directory for source file after sending";
5317 m = "new name for source file after sending";
5320 m = "new name for destination file after sending";
5324 if ((x = cmfld(m, "", &s, n == SND_MOV ? xxstring : NULL)) < 0) {
5326 printf("%s\n", n == SND_MOV ?
5327 "?Destination required" :
5328 "?New name required"
5334 if (s) if (!*s) s = NULL;
5335 makestr(&(pv[n].sval),s ? brstrip(s) : NULL);
5336 pv[n].ival = (pv[n].sval) ? 1 : 0;
5339 case SND_STA: /* Starting position (= PSEND) */
5341 if ((x = cmnum("0-based position","0",10,&y,xxstring)) < 0)
5346 case SND_TYP: /* /TYPE */
5348 if ((x = cmkey(txtbin,3,"","all",xxstring)) < 0)
5350 pv[n].ival = (x == 2) ? -1 : x;
5354 case SND_CSL: /* Local character set */
5355 case SND_CSR: /* Remote (server) charset */
5356 if ((x = cmkey(fcstab,nfilc,"","",xxstring)) < 0) {
5357 return((x == -3) ? -2 : x);
5363 x_xla = 1; /* Overrides global OFF setting */
5366 case SND_XPA: /* Transparent */
5371 #endif /* NOCSETS */
5375 if (pv[SND_RES].ival > 0) { /* /RECOVER */
5376 if (sndfilter || pv[SND_FLT].ival > 0) {
5377 printf("?Sorry, no /RECOVER or /START if SEND FILTER selected\n");
5381 if (sfttab[0] > 0 && sfttab[SFT_REST] == 0)
5382 printf("WARNING: Server says it doesn't support REST.\n");
5384 #endif /* PIPESEND */
5392 switch (cmresult.fcode) { /* How did we get out of switch loop */
5393 case _CMIFI: /* Input filename */
5394 if (pv[SND_FIL].ival > 0) {
5395 printf("?You may not give a PUT filespec and a /LISTFILE\n");
5399 ckstrncpy(line,cmresult.sresult,LINBUFSIZ); /* Name */
5400 if (pv[SND_ARR].ival > 0)
5401 ckstrncpy(asnambuf,line,CKMAXPATH);
5403 wild = cmresult.nresult; /* Wild flag */
5404 debug(F111,"ftp put wild",line,wild);
5405 if (!wild && !recursive && !mput)
5408 case _CMFLD: /* Field */
5409 /* Only allowed with /COMMAND and /ARRAY */
5410 if (pv[SND_FIL].ival > 0) {
5411 printf("?You may not give a PUT filespec and a /LISTFILE\n");
5415 /* For MPUT it's OK to have filespecs that don't match any files */
5418 if (pv[SND_CMD].ival < 1 && pv[SND_ARR].ival < 1) {
5421 printf("?Off limits: %s\n",cmresult.sresult);
5424 printf("?%s - \"%s\"\n",
5425 iswild(cmresult.sresult) ?
5426 "No files match" : "File not found",
5432 ckstrncpy(line,cmresult.sresult,LINBUFSIZ);
5433 if (pv[SND_ARR].ival > 0)
5434 ckstrncpy(asnambuf,line,CKMAXPATH);
5436 case _CMCFM: /* Confirmation */
5440 printf("?Unexpected function code: %d\n",cmresult.fcode);
5444 debug(F110,"ftp put string",s,0);
5445 debug(F101,"ftp put confirmed","",confirmed);
5447 /* Save and change protocol and transfer mode */
5448 /* Global values are restored in main parse loop */
5453 g_skipbup = skipbup;
5455 if (pv[SND_NOB].ival > -1) { /* /NOBACKUP (skip backup file) */
5456 g_skipbup = skipbup;
5459 if (pv[SND_TYP].ival > -1) { /* /TYPE */
5460 xfiletype = pv[SND_TYP].ival;
5464 if (pv[SND_BIN].ival > 0) { /* /BINARY really means binary... */
5465 forcetype = 1; /* So skip file scan */
5466 ftp_typ = FTT_BIN; /* Set binary */
5467 } else if (pv[SND_TXT].ival > 0) { /* Similarly for /TEXT... */
5470 } else if (pv[SND_TEN].ival > 0) { /* and /TENEX*/
5473 } else if (ftp_cmdlin && ftp_xfermode == XMODE_M) {
5480 if (pv[SND_CMD].ival > 0) { /* /COMMAND - strip any braces */
5481 debug(F110,"PUT /COMMAND before stripping",s,0);
5483 debug(F110,"PUT /COMMAND after stripping",s,0);
5485 printf("?Sorry, a command to send from is required\n");
5491 #endif /* PIPESEND */
5493 /* Set up /MOVE and /RENAME */
5495 if (pv[SND_DEL].ival > 0 &&
5496 (pv[SND_MOV].ival > 0 || pv[SND_REN].ival > 0)) {
5497 printf("?Sorry, /DELETE conflicts with /MOVE or /RENAME\n");
5502 if (pv[SND_MOV].ival > 0) {
5504 char * p = pv[SND_MOV].sval;
5506 if (!isdir(p)) { /* Check directory */
5509 s = (char *)malloc(len + 4);
5511 strcpy(s,p); /* safe */
5513 if (s[len-1] != ':') { s[len++] = ':'; s[len] = NUL; }
5515 if (s[len-1] != '/') { s[len++] = '/'; s[len] = NUL; }
5516 #endif /* datageneral */
5523 #endif /* NOMKDIR */
5526 printf("?Can't create \"%s\"\n",p);
5532 printf("?Directory \"%s\" not found\n",p);
5535 #endif /* CK_MKDIR */
5537 makestr(&snd_move,p);
5539 #endif /* CK_TMPDIR */
5541 if (pv[SND_REN].ival > 0) { /* /RENAME */
5542 char * p = pv[SND_REN].sval;
5545 printf("?New name required for /RENAME\n");
5551 /* If name given is wild, rename string must contain variables */
5556 if (!strcmp(tmpbuf,p)) {
5558 "?/RENAME for file group must contain variables such as \\v(filename)\n"
5565 makestr(&snd_rename,p);
5566 debug(F110,"FTP snd_rename",snd_rename,0);
5568 if (pv[SND_SRN].ival > 0) { /* /SERVER-RENAME */
5569 char * p = pv[SND_SRN].sval;
5572 printf("?New name required for /SERVER-RENAME\n");
5582 if (!strcmp(tmpbuf,p)) {
5584 "?/SERVER-RENAME for file group must contain variables such as \\v(filename)\n"
5591 makestr(&srv_renam,p);
5592 debug(F110,"ftp put srv_renam",srv_renam,0);
5594 if (!confirmed) { /* CR not typed yet, get more fields */
5596 if (mput) { /* MPUT or MMOVE */
5597 nfils = 0; /* We already have the first one */
5599 if (cmresult.fcode == _CMIFI) {
5600 /* First filespec is valid */
5601 msfiles[nfils++] = line; /* Store pointer */
5602 lp = line + (int)strlen(line) + 1; /* Point past it */
5603 debug(F111,"ftp put mput",msfiles[nfils-1],nfils-1);
5605 /* First filespec matches no files */
5606 debug(F110,"ftp put mput skipping first filespec",
5612 /* Parse a filespec, a "field", or confirmation */
5614 cmfdbi(&sf, /* 1st FDB - file to send */
5618 "", /* addtl string data */
5619 nolinks | x_recurse, /* addtl numeric data 1 */
5620 0, /* dirflg 0 means "not dirs only" */
5625 cmfdbi(&fl, /* 2nd FDB - local filespec */
5629 "", /* addtl string data */
5630 0, /* addtl numeric data 1 */
5631 0, /* addtl numeric data 2 */
5636 cmfdbi(&cm, /* 3rd FDB - Confirmation */
5648 while (!confirmed) { /* Get more filenames */
5649 x = cmfdb(&sf); /* Parse something */
5650 debug(F101,"ftp put cmfdb B","",x);
5651 debug(F101,"ftp put fcode B","",cmresult.fcode);
5652 if (x < 0) /* Error */
5653 goto xputx; /* or reparse needed */
5654 switch (cmresult.fcode) {
5655 case _CMCFM: /* End of command */
5658 debug(F100,"ftp put mput no files match","",0);
5659 printf("?No files match MPUT list\n");
5664 case _CMFLD: /* No match */
5665 debug(F110,"ftp put mput skipping",cmresult.sresult,0);
5667 case _CMIFI: /* Good match */
5668 s = cmresult.sresult;
5669 msfiles[nfils++] = lp; /* Got one, count, point to it, */
5670 p = lp; /* remember pointer, */
5671 while ((*lp++ = *s++)) /* and copy it into buffer */
5672 if (lp > (line + LINBUFSIZ)) { /* Avoid memory leak */
5673 printf("?MPUT list too long\n");
5678 debug(F111,"ftp put mput adding",msfiles[nfils-1],nfils-1);
5679 if (nfils == 1) /* Take care of \v(filespec) */
5682 zfnqfp(p,TMPBUFSIZ,tmpbuf);
5685 if (((int)strlen(fspec) + (int)strlen(p) + 1) < fspeclen) {
5686 strcat(fspec,p); /* safe */
5687 strcat(fspec," "); /* safe */
5690 printf("WARNING - \\v(filespec) buffer overflow\n");
5692 debug(F101,"doxput filespec buffer overflow","",0);
5693 #endif /* COMMENT */
5697 #endif /* NOMSEND */
5698 } else { /* Regular PUT */
5700 if ((x = cmtxt(wild ?
5701 "\nOptional as-name template containing replacement variables \
5702 like \\v(filename)" :
5703 "Optional name to send it with",
5707 if (p) if (!*p) p = NULL;
5711 makestr(&(pv[SND_ASN].sval),p);
5712 if (pv[SND_ASN].sval)
5713 pv[SND_ASN].ival = 1;
5714 debug(F110,"ftp put /as-name 2",pv[SND_ASN].sval,0);
5718 /* Set cmarg2 from as-name, however we got it. */
5721 if (pv[SND_ASN].ival > 0 && pv[SND_ASN].sval && !asnambuf[0]) {
5723 p = brstrip(pv[SND_ASN].sval);
5724 ckstrncpy(asnambuf,p,CKMAXPATH+1);
5726 debug(F110,"ftp put asnambuf",asnambuf,0);
5728 if (pv[SND_FIL].ival > 0) {
5730 if (zopeni(ZMFILE,pv[SND_FIL].sval) < 1) {
5731 debug(F110,"ftp put can't open",pv[SND_FIL].sval,0);
5732 printf("?Failure to open %s\n",pv[SND_FIL].sval);
5736 makestr(&filefile,pv[SND_FIL].sval); /* Open, remember name */
5737 debug(F110,"ftp PUT /LISTFILE opened",filefile,0);
5741 if (confirmed && !line[0] && !filefile) {
5743 if (filehead) { /* OK if we have a SEND-LIST */
5744 nfils = filesinlist;
5745 sndsrc = nfils; /* Like MSEND */
5746 addlist = 1; /* But using a different list... */
5747 filenext = filehead;
5750 #endif /* NOMSEND */
5751 printf("?Filename required but not given\n");
5756 addlist = 0; /* Don't use SEND-LIST. */
5757 #endif /* NOMSEND */
5759 if (mput) { /* MPUT (rather than PUT) */
5761 cmlist = msfiles; /* List of filespecs */
5762 sndsrc = nfils; /* rather filespec and as-name */
5763 #endif /* NOMSEND */
5765 } else if (filefile) { /* File contains list of filenames */
5772 } else if (pv[SND_ARR].ival < 1 && pv[SND_CMD].ival < 1) {
5774 /* Not MSEND, MMOVE, /LIST, or /ARRAY */
5775 nfils = sndsrc = -1;
5778 printf("?Read access denied - \"%s\"\n", s);
5783 if (s != line) /* We might already have done this. */
5784 ckstrncpy(line,s,LINBUFSIZ); /* Copy of string just parsed. */
5787 debug(F110,"doxput line=s",line,0);
5789 cmarg = line; /* File to send */
5792 zfnqfp(cmarg,fspeclen,fspec); /* Get full name */
5793 #endif /* NOMSEND */
5795 if (!mput) { /* For all but MPUT... */
5797 if (pv[SND_CMD].ival > 0) /* /COMMAND sets pipesend flag */
5799 debug(F101,"ftp put /COMMAND pipesend","",pipesend);
5800 if (pipesend && filefile) {
5801 printf("?Invalid switch combination\n");
5805 #endif /* PIPESEND */
5808 /* If as-name given and filespec is wild, as-name must contain variables */
5809 if ((wild || mput) && asnambuf[0]) {
5812 zzstring(asnambuf,&s,&x);
5813 if (!strcmp(tmpbuf,asnambuf)) {
5815 "?As-name for file group must contain variables such as \\v(filename)\n"
5826 if (pv[SND_SHH].ival > 0) { /* SEND /QUIET... */
5828 debug(F101,"ftp put display","",fdispla);
5835 #ifdef PUTARRAY /* SEND /ARRAY... */
5836 if (pv[SND_ARR].ival > 0) {
5837 if (!ap) { x = -2; goto xputx; } /* (shouldn't happen) */
5838 if (range[0] == -1) /* If low end of range not specified */
5839 range[0] = 1; /* default to 1 */
5840 if (range[1] == -1) /* If high not specified */
5841 range[1] = a_dim[arrayx]; /* default to size of array */
5842 if ((range[0] < 0) || /* Check range */
5843 (range[0] > a_dim[arrayx]) ||
5844 (range[1] < range[0]) ||
5845 (range[1] > a_dim[arrayx])) {
5846 printf("?Bad array range - [%d:%d]\n",range[0],range[1]);
5850 sndarray = ap; /* Array pointer */
5851 sndxin = arrayx; /* Array index */
5852 sndxlo = range[0]; /* Array range */
5854 sndxnam[7] = (char)((sndxin == 1) ? 64 : sndxin + ARRAYBASE);
5856 ckstrncpy(asnambuf,sndxnam,CKMAXPATH);
5859 #endif /* PUTARRAY */
5863 if (pv[SND_ARR].ival < 1) { /* File selection & disposition... */
5864 if (pv[SND_DEL].ival > 0) /* /DELETE was specified */
5866 if (pv[SND_AFT].ival > 0) /* Copy SEND criteria */
5867 ckstrncpy(sndafter,pv[SND_AFT].sval,19);
5868 if (pv[SND_BEF].ival > 0)
5869 ckstrncpy(sndbefore,pv[SND_BEF].sval,19);
5870 if (pv[SND_NAF].ival > 0)
5871 ckstrncpy(sndnafter,pv[SND_NAF].sval,19);
5872 if (pv[SND_NBE].ival > 0)
5873 ckstrncpy(sndnbefore,pv[SND_NBE].sval,19);
5874 if (pv[SND_EXC].ival > 0)
5875 makelist(pv[SND_EXC].sval,sndexcept,NSNDEXCEPT);
5876 if (pv[SND_SMA].ival > -1)
5877 sndsmaller = pv[SND_SMA].wval;
5878 if (pv[SND_LAR].ival > -1)
5879 sndlarger = pv[SND_LAR].wval;
5880 if (pv[SND_NAM].ival > -1)
5881 x_cnv = pv[SND_NAM].ival;
5882 if (pv[SND_USN].ival > -1)
5883 x_usn = pv[SND_USN].ival;
5884 if (pv[SND_ERR].ival > -1)
5885 puterror = pv[SND_ERR].ival;
5888 if (pv[SND_UPD].ival > 0) {
5890 printf("?Conflicting switches: /UPDATE /UNIQUE\n");
5894 putflags |= PUT_UPD;
5898 /* This works but it's useless, maybe dangerous */
5899 if (pv[SND_DIF].ival > 0) {
5901 printf("?Conflicting switches: /DATES-DIFFER /UNIQUE\n");
5905 putflags |= PUT_DIF;
5908 #endif /* COMMENT */
5909 #endif /* DOUPDATE */
5911 if (pv[SND_SIM].ival > 0)
5912 putflags |= PUT_SIM;
5914 if (pv[SND_PRM].ival > -1) {
5917 printf("?Conflicting switches: /PERMISSIONS /UNIQUE\n");
5921 x_prm = pv[SND_PRM].ival;
5923 printf("?/PERMISSIONS switch is not supported\n");
5927 if (pv[SND_RES].ival > 0) {
5929 printf("?PUT /RESTART can't be used because SIZE disabled.\n");
5933 if (x_usn || putflags) {
5934 printf("?Conflicting switches: /RECOVER %s\n",
5935 x_usn && putflags ? "/UNIQUE /UPDATE" :
5936 (x_usn ? "/UNIQUE" : "/UPDATE")
5943 (x_csl == FC_UCS2 ||
5946 x_csr == FC_UTF8)) {
5947 printf("?/RECOVER can not be used with Unicode translation\n");
5951 #endif /* NOCSETS */
5954 #endif /* FTP_RESTART */
5956 debug(F101,"ftp PUT restart","",putflags & PUT_RES);
5957 debug(F101,"ftp PUT update","",putflags & PUT_UPD);
5960 if (pv[SND_FLT].ival > 0) { /* Have SEND FILTER? */
5961 if (!pv[SND_FLT].sval) {
5964 sndfilter = (char *) malloc((int) strlen(pv[SND_FLT].sval) + 1);
5965 if (sndfilter) strcpy(sndfilter,pv[SND_FLT].sval); /* safe */
5967 debug(F110,"ftp put /FILTER", sndfilter, 0);
5969 if (sndfilter || pipesend) /* No /UPDATE or /RESTART */
5970 if (putflags) /* with pipes or filters */
5972 #endif /* PIPESEND */
5974 tfc = (CK_OFF_T)0; /* Initialize stats and counters */
5979 if (wild) /* (is this necessary?) */
5982 t0 = gmstimer(); /* Record starting time */
5984 done = 0; /* Loop control */
5989 while (!done && !cancelgroup) { /* Loop for all files */
5990 /* or until canceled. */
5993 If we are using a proxy, we don't use the local file list;
5994 instead we use the list on the remote machine which we want
5995 sent to someone else, and we use remglob() to get the names.
5996 But in that case we shouldn't even be executing this routine;
5999 #endif /* FTP_PROXY */
6002 x = gnfile(); /* Get next file from list(s) */
6004 if (x == 0) /* (see gnfile() comments...) */
6006 debug(F111,"FTP PUT gnfile",filnam,x);
6007 debug(F111,"FTP PUT binary",filnam,binary);
6010 case 1: /* File to send */
6013 if (asnambuf[0]) { /* As-name */
6014 int n; char *p; /* to be evaluated... */
6017 zzstring(asnambuf,&p,&n);
6019 debug(F110,"ftp put asname",s2,0);
6022 rc = putfile(cx, /* Function (PUT, APPEND) */
6023 filnam, s2, /* Name to send, as-name */
6024 forcetype, moving, /* Parameters from switches... */
6025 snd_move, snd_rename, srv_renam,
6026 x_cnv, x_usn, xfiletype, x_prm,
6028 x_csl, (!x_xla ? -1 : x_csr),
6031 #endif /* NOCSETS */
6034 debug(F111,"ftp put putfile rc",filnam,rc);
6035 debug(F111,"ftp put putfile cancelfile",filnam,cancelfile);
6036 debug(F111,"ftp put putfile cancelgroup",filnam,cancelgroup);
6047 printf("?Fatal upload error: %s\n",filnam);
6052 case 0: /* No more files, done */
6056 printf("?%s: file not found - \"%s\"\n",
6057 puterror ? "Fatal" : "Warning",
6068 printf("?Fatal: file not found - \"%s\"\n", filnam);
6073 continue; /* Not readable, keep going */
6076 printf("?Fatal: Read access denied - \"%s\"\n", filnam);
6081 printf("?Warning access denied - \"%s\"\n", filnam);
6084 case -4: /* Canceled */
6087 #endif /* COMMENT */
6089 printf("?Too many files match\n");
6094 printf("?No files selected\n");
6098 printf("?getnextfile() - unknown failure\n");
6106 } else if (!doftpcdup())
6113 else if (cancelfile && good < 1)
6122 t1 = gmstimer(); /* End time */
6123 sec = (CKFLOAT)((CKFLOAT)(t1 - t0) / 1000.0); /* Stats */
6124 if (!sec) sec = 0.001;
6127 sec = (t1 - t0) / 1000;
6129 #endif /* GFTIMER */
6130 tfcps = (long) (tfc / sec);
6132 lastxfer = W_FTP|W_SEND;
6135 ftscreen(status > 0 ? SCR_TC : SCR_CW, 0, (CK_OFF_T)0, "");
6137 for (i = 0; i <= SND_MAX; i++) { /* Free malloc'd memory */
6141 ftreset(); /* Undo switch effects */
6147 static char ** mgetlist = NULL; /* For MGET */
6148 static int mgetn = 0, mgetx = 0;
6149 static char xtmpbuf[4096];
6154 Get files specified by -g command-line option.
6155 File list is set up in cmlist[] by ckuusy.c; nfils is length of list.
6158 cmdlinget(stay) int stay; {
6159 int i, x, rc = 0, done = 0, good = 0, status = 0, append = 0;
6160 int lcs = -1, rcs = -1, xlate = 0;
6164 char * s, * s2, * s3;
6165 ULONG t0, t1; /* Times for stats */
6170 #endif /* GFTIMER */
6172 if (quiet) { /* -q really means quiet */
6182 what = W_FTP|W_RECV;
6187 havesize = (CK_OFF_T)-1;
6188 makestr(&havemdtm,NULL);
6196 debug(F101,"ftp cmdlinget nfils","",nfils);
6198 if (ftp_cnv == CNV_AUTO) { /* Name conversion is auto */
6199 if (alike) { /* If server & client are alike */
6200 nc = 0; /* no conversion */
6201 } else { /* If they are different */
6202 if (servertype == SYS_UNIX || servertype == SYS_WIN32)
6203 nc = -1; /* only minimal conversions needed */
6204 else /* otherwise */
6205 nc = 1; /* full conversion */
6207 } else /* Not auto - do what user said */
6211 doexit(BAD_EXIT,-1);
6213 t0 = gmstimer(); /* Starting time for this batch */
6216 if (xlate) { /* SET FTP CHARACTER-SET-TRANSLATION */
6217 lcs = ftp_csl; /* Local charset */
6218 if (lcs < 0) lcs = fcharset;
6219 if (lcs < 0) xlate = 0;
6221 if (xlate) { /* Still ON? */
6222 rcs = ftp_csx; /* Remote (Server) charset */
6223 if (rcs < 0) rcs = ftp_csr;
6224 if (rcs < 0) xlate = 0;
6226 #endif /* NOCSETS */
6228 If we have only one file and it is a directory, then we ask for a
6229 listing of its contents, rather than retrieving the directory file
6230 itself. This is what (e.g.) Netscape does.
6233 if (doftpcwd((char *)cmlist[mgetx],-1)) {
6234 /* If we can CD to it, it must be a directory */
6236 cmlist[mgetx] = "*";
6239 (recvrequest("LIST","-","","wb",0,0,NULL,xlate,lcs,rcs)==0);
6245 The following is to work around UNIX servers which, when given a command
6246 like "NLST path/blah" (not wild) returns the basename without the path.
6248 if (!done && servertype == SYS_UNIX && nfils == 1) {
6249 mget = iswild(cmlist[mgetx]);
6251 if (!mget && !done) { /* Invoked by command-line FTP URL */
6253 printf("DOING GET...\n");
6255 cancelfile = 0; /* This file not canceled yet */
6257 rc = 0; /* Initial return code */
6258 fsize = (CK_OFF_T)-1;
6260 x = ftpcmd("SIZE",s,lcs,rcs,ftp_vbm); /* Get remote file's size */
6261 if (x == REPLY_COMPLETE)
6262 fsize = ckatofs(&ftp_reply_str[4]);
6264 ckstrncpy(filnam,s,CKMAXPATH); /* For \v(filename) */
6265 debug(F111,"ftp cmdlinget filnam",filnam,fsize);
6267 nzrtol(s,tmpbuf,nc,0,CKMAXPATH); /* Strip path and maybe convert */
6270 /* If local file already exists, take collision action */
6272 if (zchki(s2) > -1) {
6274 case XYFX_A: /* Append */
6277 case XYFX_R: /* Rename */
6278 case XYFX_B: { /* Backup */
6281 znewn(s2,&p); /* Make unique name */
6282 debug(F110,"ftp cmdlinget znewn",p,0);
6283 if (ftp_fnc == XYFX_B) { /* Backup existing file */
6285 debug(F111,"ftp cmdlinget backup zrename",p,x);
6286 } else { /* Rename incoming file */
6287 x = ckstrncpy(tmpbuf,p,CKMAXPATH+1);
6289 debug(F111,"ftp cmdlinget rename incoming",p,x);
6292 printf("?Backup/Rename failed\n");
6293 return(success = 0);
6297 case XYFX_D: /* Discard */
6298 ftscreen(SCR_FN,'F',(CK_OFF_T)0,s);
6299 ftscreen(SCR_ST,ST_SKIP,(CK_OFF_T)SKP_NAM,s);
6300 tlog(F100," refused: name","",0);
6301 debug(F110,"ftp cmdlinget skip name",s2,0);
6304 case XYFX_X: /* Overwrite */
6305 case XYFX_U: /* Update (already handled above) */
6306 case XYFX_M: /* ditto */
6310 rc = getfile(s, /* Remote name */
6311 s2, /* Local name */
6312 0, /* Recover/Restart */
6313 append, /* Append */
6314 NULL, /* Pipename */
6315 0, /* Translate charsets */
6316 -1, /* File charset (none) */
6317 -1 /* Server charset (none) */
6319 debug(F111,"ftp cmdlinget rc",s,rc);
6320 debug(F111,"ftp cmdlinget cancelfile",s,cancelfile);
6321 debug(F111,"ftp cmdlinget cancelgroup",s,cancelgroup);
6323 if (rc < 0 && haveurl && s[0] == '/') /* URL failed - try again */
6324 rc = getfile(&s[1], /* Remote name without leading '/' */
6325 s2, /* Local name */
6326 0, /* Recover/Restart */
6327 append, /* Append */
6328 NULL, /* Pipename */
6329 0, /* Translate charsets */
6330 -1, /* File charset (none) */
6331 -1 /* Server charset (none) */
6344 #endif /* FTP_TIMEOUT */
6351 if (ftp_deb && !done)
6352 printf("DOING MGET...\n");
6353 while (!done && !cancelgroup) {
6354 cancelfile = 0; /* This file not canceled yet */
6355 s = (char *)remote_files(first,(CHAR *)cmlist[mgetx],NULL,0);
6361 s = (char *)remote_files(first,(CHAR *)cmlist[mgetx],NULL,0);
6364 debug(F111,"ftp cmdlinget remote_files B",s,0);
6371 The semantics of NLST are ill-defined. Suppose we have just sent
6372 NLST /path/[a-z]*. Most servers send back names like /path/foo,
6373 /path/bar, etc. But some send back only foo and bar, and subsequent
6374 RETR commands based on the pathless names are not going to work.
6376 if (servertype == SYS_UNIX && !ckstrchr(s,'/')) {
6377 if ((s3 = ckstrrchr(cmlist[mgetx],'/'))) {
6378 int len, left = 4096;
6379 char * tmp = xtmpbuf;
6380 len = s3 - cmlist[mgetx] + 1;
6381 ckstrncpy(tmp,cmlist[mgetx],left);
6384 ckstrncpy(tmp,s,left);
6386 debug(F111,"ftp cmdlinget remote_files X",s,0);
6389 first = 0; /* Not first any more */
6391 debug(F111,"ftp cmdlinget havetype",s,havetype);
6392 if (havetype > 0 && havetype != FTYP_FILE) { /* Server says not file */
6393 debug(F110,"ftp cmdlinget not-a-file",s,0);
6396 rc = 0; /* Initial return code */
6397 if (havesize > (CK_OFF_T)-1) { /* Already have file size? */
6399 } else { /* No - must ask server */
6401 Prior to sending the NLST command we necessarily put the
6402 server into ASCII mode. We must now put it back into the
6403 the requested mode so the upcoming SIZE command returns
6404 right kind of size; this is especially important for
6405 GET /RECOVER; otherwise the server returns the "ASCII" size
6406 of the file, rather than its true size.
6408 changetype(ftp_typ,0); /* Change to requested type */
6409 fsize = (CK_OFF_T)-1;
6411 x = ftpcmd("SIZE",s,lcs,rcs,ftp_vbm);
6412 if (x == REPLY_COMPLETE)
6413 fsize = ckatofs(&ftp_reply_str[4]);
6416 ckstrncpy(filnam,s,CKMAXPATH); /* For \v(filename) */
6417 debug(F111,"ftp cmdlinget filnam",filnam,fsize);
6419 nzrtol(s,tmpbuf,nc,0,CKMAXPATH); /* Strip path and maybe convert */
6422 /* If local file already exists, take collision action */
6424 if (zchki(s2) > -1) {
6426 case XYFX_A: /* Append */
6429 case XYFX_R: /* Rename */
6430 case XYFX_B: { /* Backup */
6433 znewn(s2,&p); /* Make unique name */
6434 debug(F110,"ftp cmdlinget znewn",p,0);
6435 if (ftp_fnc == XYFX_B) { /* Backup existing file */
6437 debug(F111,"ftp cmdlinget backup zrename",p,x);
6438 } else { /* Rename incoming file */
6439 x = ckstrncpy(tmpbuf,p,CKMAXPATH+1);
6441 debug(F111,"ftp cmdlinget rename incoming",p,x);
6444 printf("?Backup/Rename failed\n");
6445 return(success = 0);
6449 case XYFX_D: /* Discard */
6450 ftscreen(SCR_FN,'F',(CK_OFF_T)0,s);
6451 ftscreen(SCR_ST,ST_SKIP,(CK_OFF_T)SKP_NAM,s);
6452 tlog(F100," refused: name","",0);
6453 debug(F110,"ftp cmdlinget skip name",s2,0);
6455 case XYFX_X: /* Overwrite */
6456 case XYFX_U: /* Update (already handled above) */
6457 case XYFX_M: /* ditto */
6461 /* ^^^ ADD CHARSET STUFF HERE ^^^ */
6462 rc = getfile(s, /* Remote name */
6463 s2, /* Local name */
6464 0, /* Recover/Restart */
6465 append, /* Append */
6466 NULL, /* Pipename */
6467 0, /* Translate charsets */
6468 -1, /* File charset (none) */
6469 -1 /* Server charset (none) */
6471 debug(F111,"ftp cmdlinget rc",s,rc);
6472 debug(F111,"ftp cmdlinget cancelfile",s,cancelfile);
6473 debug(F111,"ftp cmdlinget cancelgroup",s,cancelgroup);
6486 #endif /* FTP_TIMEOUT */
6500 else if (cancelfile && good < 1)
6506 t1 = gmstimer(); /* End time */
6507 sec = (CKFLOAT)((CKFLOAT)(t1 - t0) / 1000.0); /* Stats */
6508 if (!sec) sec = 0.001;
6511 sec = (t1 - t0) / 1000;
6513 #endif /* GFTIMER */
6515 tfcps = (long) (tfc / sec);
6517 lastxfer = W_FTP|W_RECV;
6520 ftscreen(status > 0 ? SCR_TC : SCR_CW, 0, (CK_OFF_T)0, "");
6522 doexit(success ? GOOD_EXIT : BAD_EXIT, -1);
6526 /* d o f t p g e t -- Parse and execute GET, MGET, MDELETE, ... */
6529 Note: if we wanted to implement /AFTER:, /BEFORE:, etc, we could use
6530 zstrdat() to convert to UTC-based time_t. But it doesn't make sense from
6531 the user-interface perspective, since the server's directory listings show
6532 its own local times and since we don't know what timezone it's in, there's
6533 no way to reconcile our local times with the server's.
6536 doftpget(cx,who) int cx, who; { /* who == 1 for ftp, 0 for kermit */
6537 struct FDB fl, sw, cm;
6538 int i, n, rc, getval = 0, mget = 0, done = 0, pipesave = 0;
6539 int x_cnv = 0, x_prm = 0, restart = 0, status = 0, good = 0;
6540 int x_fnc = 0, first = 0, skipthis = 0, append = 0, selected = 0;
6541 int renaming = 0, mdel = 0, listfile = 0, updating = 0, getone = 0;
6542 int moving = 0, deleting = 0, toscreen = 0, haspath = 0;
6545 CK_OFF_T getlarger = (CK_OFF_T)-1;
6546 CK_OFF_T getsmaller = (CK_OFF_T)-1;
6547 char * msg, * s, * s2, * nam, * pipename = NULL, * pn = NULL;
6548 char * src = "", * local = "";
6551 int x_csl = -1, x_csr = -1; /* Local and remote charsets */
6553 char c; /* Worker char */
6554 ULONG t0 = 0L, t1; /* Times for stats */
6559 #endif /* GFTIMER */
6561 struct stringint pv[SND_MAX+1]; /* Temporary array for switch values */
6563 success = 0; /* Assume failure */
6564 forcetype = 0; /* No /TEXT or /BINARY given yet */
6565 restart = 0; /* No restart yet */
6566 out2screen = 0; /* No TO-SCREEN switch given yet */
6567 mgetmethod = 0; /* No NLST or MLSD switch yet */
6574 x_cnv = ftp_cnv; /* Filename conversion */
6575 if (x_cnv == CNV_AUTO) { /* Name conversion is auto */
6576 if (alike) { /* If server & client are alike */
6577 x_cnv = 0; /* no conversion */
6578 } else { /* If they are different */
6579 if (servertype == SYS_UNIX || servertype == SYS_WIN32)
6580 x_cnv = -1; /* only minimal conversions needed */
6581 else /* otherwise */
6582 x_cnv = 1; /* full conversion */
6584 } else /* Not auto - do what user said */
6587 x_prm = ftp_prm; /* Permissions */
6588 if (x_prm == SET_AUTO) /* Permissions AUTO */
6592 x_csr = ftp_csr; /* Inherit global server charset */
6593 x_csl = ftp_csl; /* Inherit global local charset */
6594 if (x_csl < 0) /* If none, use current */
6595 x_csl = fcharset; /* file character-set. */
6596 x_xla = ftp_xla; /* Translation On/Off */
6597 #endif /* NOCSETS */
6599 geterror = ftp_err; /* Inherit global error action. */
6600 asnambuf[0] = NUL; /* No as-name yet. */
6601 pipesave = pipesend;
6605 havesize = (CK_OFF_T)-1;
6606 makestr(&havemdtm,NULL);
6608 if (g_ftp_typ > -1) { /* Restore TYPE if saved */
6609 ftp_typ = g_ftp_typ;
6610 /* g_ftp_typ = -1; */
6612 for (i = 0; i <= SND_MAX; i++) { /* Initialize switch values */
6613 pv[i].sval = NULL; /* to null pointers */
6614 pv[i].ival = -1; /* and -1 int values */
6615 pv[i].wval = (CK_OFF_T)-1; /* and -1 wide values */
6617 zclose(ZMFILE); /* In case it was left open */
6619 x_fnc = ftp_fnc > -1 ? ftp_fnc : fncact; /* Filename collision action */
6621 if (fp_nml) { /* Reset /NAMELIST */
6622 if (fp_nml != stdout)
6626 makestr(&ftp_nml,NULL);
6628 /* Initialize list of remote filespecs */
6631 mgetlist = (char **)malloc(MGETMAX * sizeof(char *));
6633 printf("?Memory allocation failure - MGET list\n");
6636 for (i = 0; i < MGETMAX; i++)
6639 mgetn = 0; /* Number of mget arguments */
6640 mgetx = 0; /* Current arg */
6642 if (who == 0) { /* Called with unprefixed command */
6643 if (cx == XXGET || cx == XXREGET || cx == XXRETR)
6646 case XXREGET: pv[SND_RES].ival = 1; break;
6647 case XXRETR: pv[SND_DEL].ival = 1; break;
6649 case XXMGET: mget++; break;
6651 } else { /* FTP command */
6652 if (cx == FTP_GET || cx == FTP_RGE)
6655 case FTP_DEL: /* (fall thru on purpose) */
6656 case FTP_MDE: mdel++; /* (ditto) */
6657 case FTP_GET: /* (ditto) */
6658 case FTP_MGE: mget++; break;
6659 case FTP_RGE: pv[SND_RES].ival = 1; break;
6662 cmfdbi(&sw, /* First FDB - command switches */
6664 "Remote filename;\n or switch", /* hlpmsg */
6666 "", /* addtl string data */
6667 mdel ? ndelswi : ngetswi, /* addtl numeric data 1: tbl size */
6668 4, /* addtl numeric data 2: 4 = cmswi */
6669 xxstring, /* Processing function */
6670 mdel ? delswi : getswi, /* Keyword table */
6671 &fl /* Pointer to next FDB */
6673 cmfdbi(&fl, /* 2nd FDB - remote filename */
6677 "", /* addtl string data */
6678 0, /* addtl numeric data 1 */
6679 0, /* addtl numeric data 2 */
6684 cmfdbi(&cm, /* 3rd FDB - Confirmation */
6688 "", /* addtl string data */
6689 0, /* addtl numeric data 1 */
6690 0, /* addtl numeric data 2 */
6696 while (1) { /* Parse 0 or more switches */
6697 x = cmfdb(&sw); /* Parse something */
6698 debug(F101,"ftp get cmfdb","",x);
6699 if (x < 0) /* Error */
6700 goto xgetx; /* or reparse needed */
6701 if (cmresult.fcode != _CMKEY) /* Break out of loop if not a switch */
6703 c = cmgbrk(); /* Get break character */
6704 getval = (c == ':' || c == '='); /* to see how they ended the switch */
6705 if (getval && !(cmresult.kflags & CM_ARG)) {
6706 printf("?This switch does not take arguments\n");
6710 n = cmresult.nresult; /* Numeric result = switch value */
6711 debug(F101,"ftp get switch","",n);
6713 if (!getval && (cmgkwflgs() & CM_ARG)) {
6714 printf("?This switch requires an argument\n");
6718 switch (n) { /* Process the switch */
6719 case SND_ASN: /* /AS-NAME: */
6720 debug(F101,"ftp get /as-name getval","",getval);
6722 if ((x = cmfld("Name to store it under","",&s,NULL)) < 0) {
6724 printf("?name required\n");
6731 makestr(&(pv[n].sval),s);
6735 case SND_BIN: /* /BINARY */
6736 case SND_TXT: /* /TEXT or /ASCII */
6737 case SND_TEN: /* /TENEX */
6738 pv[SND_BIN].ival = 0;
6739 pv[SND_TXT].ival = 0;
6740 pv[SND_TEN].ival = 0;
6745 case SND_CMD: /* These take no args */
6747 printf("?Sorry, system command access is disabled\n");
6752 else if (rcvfilter) {
6753 printf("?Sorry, no PUT /COMMAND when SEND FILTER selected\n");
6757 #endif /* PIPESEND */
6758 sw.hlpmsg = "Command, or switch"; /* Change help message */
6759 pv[n].ival = 1; /* Just set the flag */
6760 pv[SND_ARR].ival = 0;
6762 #endif /* PUTPIPE */
6764 case SND_SHH: /* /QUIET */
6765 case SND_RES: /* /RECOVER (reget) */
6766 case SND_NOB: /* /NOBACKUPFILES */
6767 case SND_DEL: /* /DELETE */
6768 case SND_UPD: /* /UPDATE */
6769 case SND_USN: /* /UNIQUE */
6770 case SND_NOD: /* /NODOTFILES */
6771 case SND_REC: /* /RECOVER */
6772 case SND_MAI: /* /TO-SCREEN */
6773 pv[n].ival = 1; /* Just set the flag */
6776 case SND_DIF: /* /DATES-DIFFER */
6777 pv[SND_COL].ival = XYFX_M; /* Now it's a collision option */
6781 case SND_COL: /* /COLLISION: */
6782 if ((x = cmkey(ftpcolxtab,nftpcolx,"","",xxstring)) < 0)
6785 pv[SND_DIF].ival = 1; /* (phase this out) */
6786 pv[n].ival = x; /* this should be sufficient */
6789 case SND_ERR: /* /ERROR-ACTION */
6790 if ((x = cmkey(qorp,2,"","",xxstring)) < 0)
6795 case SND_EXC: /* Exception list */
6797 if ((x = cmfld("Pattern","",&s,xxstring)) < 0) {
6799 printf("?Pattern required\n");
6804 if (s) if (!*s) s = NULL;
6805 makestr(&(pv[n].sval),s);
6812 debug(F101,"ftp get /filter getval","",getval);
6814 if ((x = cmfld("Filter program to send through","",&s,NULL)) < 0) {
6821 if (pv[SND_MAI].ival < 1) {
6823 /* Make sure they included "\v(...)" */
6824 for (x = 0; x < y; x++) {
6825 if (s[x] != '\\') continue;
6826 if (s[x+1] == 'v') break;
6830 "?Filter must contain a replacement variable for filename.\n"
6838 makestr(&(pv[n].sval),s);
6841 makestr(&(pv[n].sval),NULL);
6844 #endif /* PIPESEND */
6848 if ((x = cmkey(fntab,nfntab,"","automatic",xxstring)) < 0)
6850 debug(F101,"ftp get /filenames","",x);
6854 case SND_SMA: /* Smaller / larger than */
6858 if ((x = cmnumw("Size in bytes","0",10,&y,xxstring)) < 0)
6863 case SND_FIL: /* Name of file containing filnames */
6865 if ((x = cmifi("Name of file containing list of filenames",
6866 "",&s,&y,xxstring)) < 0) {
6868 printf("?Filename required\n");
6872 } else if (y && iswild(s)) {
6873 printf("?Wildcards not allowed BBB\n");
6877 if (s) if (!*s) s = NULL;
6878 makestr(&(pv[n].sval),s);
6883 case SND_MOV: /* MOVE after */
6884 case SND_REN: /* RENAME after */
6885 case SND_SRN: { /* SERVER-RENAME */
6890 "Device and/or directory for incoming file after reception";
6893 m = "New name for incoming file after reception";
6896 m = "New name for source file on server after reception";
6900 if ((x = cmfld(m, "", &s, n == SND_MOV ? xxstring : NULL)) < 0) {
6902 printf("%s\n", n == SND_MOV ?
6903 "?Destination required" :
6904 "?New name required"
6910 makestr(&(pv[n].sval),*s ? brstrip(s) : NULL);
6911 pv[n].ival = (pv[n].sval) ? 1 : 0;
6915 case SND_CSL: /* Local character set */
6916 case SND_CSR: /* Remote (server) charset */
6917 if ((x = cmkey(fcstab,nfilc,"","",xxstring)) < 0)
6918 return((x == -3) ? -2 : x);
6923 x_xla = 1; /* Overrides global OFF setting */
6926 case SND_XPA: /* Transparent */
6931 #endif /* NOCSETS */
6934 if ((x = cmofi("Local filename","-",&s,xxstring)) < 0)
6936 makestr(&ftp_nml,s);
6939 case SND_PAT: /* /PATTERN: */
6941 if ((x = cmfld("Pattern","*", &s, xxstring)) < 0)
6943 makestr(&(pv[n].sval),*s ? brstrip(s) : NULL);
6944 pv[n].ival = (pv[n].sval) ? 1 : 0;
6947 case SND_NLS: /* /NLST */
6948 pv[n].ival = 1; /* Use NLST */
6949 pv[SND_MLS].ival = 0; /* Don't use MLSD */
6952 case SND_MLS: /* /MLSD */
6953 pv[n].ival = 1; /* Use MLSD */
6954 pv[SND_NLS].ival = 0; /* Don't use NLST */
6957 default: /* /AFTER, /PERMISSIONS, etc... */
6958 printf("?Sorry, \"%s\" works only with [M]PUT\n",atmbuf);
6968 For GET, we want to parse an optional as-name, like with PUT.
6969 For MGET, we must parse a list of names, and then send NLST or MLSD
6970 commands for each name separately.
6972 switch (cmresult.fcode) { /* How did we get out of switch loop */
6973 case _CMFLD: /* Field */
6975 s = brstrip(cmresult.sresult);
6976 makestr(&(mgetlist[mgetn++]),s);
6977 while ((x = cmfld("Remote filename","",&s,xxstring)) != -3) {
6980 makestr(&(mgetlist[mgetn++]),brstrip(s));
6981 if (mgetn >= MGETMAX) {
6982 printf("?Too many items in MGET list\n");
6986 if ((x = cmcfm()) < 0)
6989 s = brstrip(cmresult.sresult);
6990 ckstrncpy(line,s,LINBUFSIZ);
6991 if ((x = cmfld("Name to store it under","",&s,xxstring)) < 0)
6995 ckstrncpy(asnambuf,s,CKMAXPATH+1);
6996 if ((x = cmcfm()) < 0)
7000 case _CMCFM: /* Confirmation */
7003 printf("?Unexpected function code: %d\n",cmresult.fcode);
7007 if (pv[SND_REC].ival > 0) /* /RECURSIVE */
7010 if (pv[SND_BIN].ival > 0) { /* /BINARY really means binary... */
7011 forcetype = 1; /* So skip the name-pattern match */
7012 ftp_typ = XYFT_B; /* Set binary */
7013 } else if (pv[SND_TXT].ival > 0) { /* Similarly for /TEXT... */
7016 } else if (pv[SND_TEN].ival > 0) { /* and /TENEX*/
7019 } else if (ftp_cmdlin && ftp_xfermode == XMODE_M) {
7024 if (pv[SND_ASN].ival > 0 && pv[SND_ASN].sval && !asnambuf[0]) {
7026 p = brstrip(pv[SND_ASN].sval); /* As-name */
7027 ckstrncpy(asnambuf,p,CKMAXPATH+1);
7029 debug(F110,"ftp get asnambuf",asnambuf,0);
7032 if (pv[SND_CMD].ival > 0) { /* /COMMAND - strip any braces */
7035 debug(F110,"GET /COMMAND before stripping",p,0);
7037 debug(F110,"GET /COMMAND after stripping",p,0);
7039 printf("?Sorry, a command to write to is required\n");
7046 #endif /* PIPESEND */
7048 /* Set up /MOVE and /RENAME */
7051 /* Conflict exists only for PUT - removed 13 Mar 2006 - fdc */
7052 if (pv[SND_DEL].ival > 0 &&
7053 (pv[SND_MOV].ival > 0 || pv[SND_REN].ival > 0)) {
7054 printf("?Sorry, /DELETE conflicts with /MOVE or /RENAME\n");
7058 #endif /* COMMENT */
7060 if (pv[SND_MOV].ival > 0 && pv[SND_MOV].sval) {
7062 char * p = pv[SND_MOV].sval;
7064 if (!isdir(p)) { /* Check directory */
7067 s = (char *)malloc(len + 4);
7069 strcpy(s,p); /* safe */
7071 if (s[len-1] != ':') { s[len++] = ':'; s[len] = NUL; }
7073 if (s[len-1] != '/') { s[len++] = '/'; s[len] = NUL; }
7074 #endif /* datageneral */
7081 #endif /* NOMKDIR */
7084 printf("?Can't create \"%s\"\n",p);
7090 printf("?Directory \"%s\" not found\n",p);
7093 #endif /* CK_MKDIR */
7095 makestr(&rcv_move,p);
7098 #endif /* CK_TMPDIR */
7100 if (pv[SND_REN].ival > 0) { /* /RENAME */
7101 char * p = pv[SND_REN].sval;
7104 printf("?New name required for /RENAME\n");
7110 /* If name given is wild, rename string must contain variables */
7111 if (mget && !getone) {
7115 if (!strcmp(tmpbuf,p)) {
7117 "?/RENAME for file group must contain variables such as \\v(filename)\n"
7125 makestr(&rcv_rename,p);
7126 debug(F110,"FTP rcv_rename",rcv_rename,0);
7128 if (!cmarg[0] && mgetn == 0 && getone && pv[SND_FIL].ival < 1) {
7129 printf("?Filename required but not given\n");
7132 } else if ((cmarg[0] || mgetn > 0) && pv[SND_FIL].ival > 0) {
7133 printf("?You can't give both /LISTFILE and a remote filename\n");
7137 CHECKCONN(); /* Check connection */
7139 if (pv[SND_COL].ival > -1)
7140 x_fnc = pv[SND_COL].ival;
7143 /* If as-name given for MGET, as-name must contain variables */
7144 if (mget && !getone && asnambuf[0] && x_fnc != XYFX_A) {
7147 zzstring(asnambuf,&s,&x);
7148 if (!strcmp(tmpbuf,asnambuf)) {
7150 "?As-name for MGET must contain variables such as \\v(filename)\n"
7160 if (pv[SND_SHH].ival > 0 || ftp_nml) { /* GET /QUIET... */
7164 if (mdel || ftp_deb)
7168 if (pv[SND_DEL].ival > 0) /* /DELETE was specified */
7170 if (pv[SND_EXC].ival > 0)
7171 makelist(pv[SND_EXC].sval,rcvexcept,NSNDEXCEPT);
7172 if (pv[SND_SMA].wval > -1)
7173 getsmaller = pv[SND_SMA].wval;
7174 if (pv[SND_LAR].wval > -1)
7175 getlarger = pv[SND_LAR].wval;
7176 if (pv[SND_NAM].ival > -1)
7177 x_cnv = pv[SND_NAM].ival;
7178 if (pv[SND_ERR].ival > -1)
7179 geterror = pv[SND_ERR].ival;
7180 if (pv[SND_MAI].ival > -1)
7183 if (pv[SND_NLS].ival > 0) { /* Force NLST or MLSD? */
7184 mgetmethod = SND_NLS;
7186 } else if (pv[SND_MLS].ival > 0) {
7187 mgetmethod = SND_MLS;
7192 if (pv[SND_RES].ival > 0) {
7194 printf("?Sorry, GET /RECOVER requires binary mode\n");
7198 /* Not true - the fact that the initial REST fails does not mean */
7199 /* it will fail here. */
7200 } else if (!okrestart) {
7201 printf("WARNING: Server might not support restart...\n");
7202 #endif /* COMMENT */
7206 #endif /* FTP_RESTART */
7209 if (pv[SND_FLT].ival > 0) { /* Have SEND FILTER? */
7211 printf("?Switch conflict: /FILTER and /COMMAND\n");
7215 makestr(&rcvfilter,pv[SND_FLT].sval);
7216 debug(F110,"ftp get /FILTER", rcvfilter, 0);
7218 if (rcvfilter || pipesend) { /* /RESTART */
7220 if (restart) { /* with pipes or filters */
7221 printf("?Switch conflict: /FILTER or /COMMAND and /RECOVER\n");
7225 #endif /* FTP_RESTART */
7226 if (pv[SND_UPD].ival > 0 || x_fnc == XYFX_M || x_fnc == XYFX_U) {
7228 "?Switch conflict: /FILTER or /COMMAND and Date Checking\n");
7233 #endif /* PIPESEND */
7235 tfc = (CK_OFF_T)0; /* Initialize stats and counters */
7240 if (pv[SND_FIL].ival > 0) {
7241 if (zopeni(ZMFILE,pv[SND_FIL].sval) < 1) {
7242 debug(F111,"ftp get can't open listfile",pv[SND_FIL].sval,errno);
7243 printf("?Failure to open listfile - \"%s\"\n",pv[SND_FIL].sval);
7247 if (zsinl(ZMFILE,tmpbuf,CKMAXPATH) < 0) { /* Read a line */
7248 zclose(ZMFILE); /* Failed */
7249 debug(F110,"ftp get listfile EOF",pv[SND_FIL].sval,0);
7250 printf("?Empty listfile - \"%s\"\n",pv[SND_FIL].sval);
7255 debug(F110,"ftp get listfile first",tmpbuf,0);
7256 makestr(&(mgetlist[0]),tmpbuf);
7258 t0 = gmstimer(); /* Record starting time */
7260 updating = 0; /* Checking dates? */
7261 if (pv[SND_UPD].ival > 0 || (!mdel && x_fnc == XYFX_U))
7263 if (pv[SND_DIF].ival > 0 || x_fnc == XYFX_M)
7265 if (updating) /* These switches force FTP DATES ON */
7268 what = mdel ? W_FTP|W_FT_DELE : W_RECV|W_FTP; /* What we're doing */
7270 cancelgroup = 0; /* Group not canceled yet */
7271 if (!(ftp_xfermode == XMODE_A && patterns && get_auto && !forcetype))
7272 changetype(ftp_typ,0); /* Change to requested type */
7273 binary = ftp_typ; /* For file-transfer display */
7274 first = 1; /* For MGET list */
7275 done = 0; /* Loop control */
7278 if (dldir && !f_tmpdir) { /* If they have a download directory */
7279 if ((s = zgtdir())) { /* Get current directory */
7280 if (zchdir(dldir)) { /* Change to download directory */
7281 ckstrncpy(savdir,s,TMPDIRLEN);
7282 f_tmpdir = 1; /* Remember that we did this */
7286 #endif /* CK_TMPDIR */
7288 if (ftp_nml) { /* /NAMELIST */
7289 debug(F110,"ftp GET ftp_nml",ftp_nml,0);
7290 if (ftp_nml[0] == '-' && ftp_nml[1] == 0)
7293 fp_nml = fopen(ftp_nml, "wb");
7295 printf("?%s: %s\n",ftp_nml,ck_errstr());
7299 while (!done && !cancelgroup) { /* Loop for all files */
7300 /* or until canceled. */
7302 /* do something here if proxy */
7303 #endif /* FTP_PROXY */
7305 rs_len = (CK_OFF_T)0; /* REGET position */
7306 cancelfile = 0; /* This file not canceled yet */
7307 haspath = 0; /* Recalculate this each time thru */
7309 if (getone) { /* GET */
7312 src = line; /* Server name */
7314 debug(F111,"ftp get file",s,0);
7315 } else if (mget) { /* MGET */
7316 src = mgetlist[mgetx];
7317 debug(F111,"ftp mget remote_files A",src,first);
7318 s = (char *)remote_files(first,
7319 (CHAR *)mgetlist[mgetx],
7320 (CHAR *)pv[SND_PAT].sval,
7323 debug(F110,"ftp mget remote_files B",s,0);
7327 if (listfile) { /* Names from listfile */
7330 while (!tmpbuf[0]) {
7331 if (zsinl(ZMFILE,tmpbuf,CKMAXPATH) < 0) {
7333 debug(F110,"ftp get listfile EOF",
7334 pv[SND_FIL].sval,0);
7335 makestr(&(mgetlist[0]),NULL);
7344 makestr(&(mgetlist[0]),tmpbuf);
7345 debug(F110,"ftp get listfile next",tmpbuf,0);
7346 s = (char *)remote_files(first,
7347 (CHAR *)mgetlist[0],
7348 (CHAR *)pv[SND_PAT].sval,
7351 debug(F110,"ftp mget remote_files C",s,0);
7353 ftscreen(SCR_FN,'F',(CK_OFF_T)0,s);
7354 ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,"File not found");
7355 tlog(F110,"ftp get file not found:",s,0);
7358 } else { /* Names from command line */
7361 s = (char *)remote_files(first,
7362 (CHAR *)mgetlist[mgetx],
7363 (CHAR *)pv[SND_PAT].sval,
7369 debug(F111,"ftp mget remote_files D",s,mgetx);
7372 if (!first || mgetx >= mgetn) {
7375 } else if (geterror) {
7385 debug(F111,"ftp mget remote_files E",s,0);
7387 The semantics of NLST are ill-defined. Suppose we have just sent
7388 NLST /path/[a-z]*. Most servers send back names like /path/foo,
7389 /path/bar, etc. But some send back only foo and bar, and subsequent
7390 RETR commands based on the pathless names are not going to work.
7392 if (servertype == SYS_UNIX && !ckstrchr(s,'/')) {
7394 if ((s3 = ckstrrchr(mgetlist[mgetx],'/'))) {
7395 int len, left = 4096;
7396 char * tmp = xtmpbuf;
7397 len = s3 - mgetlist[mgetx] + 1;
7398 ckstrncpy(tmp,mgetlist[mgetx],left);
7401 ckstrncpy(tmp,s,left);
7403 debug(F111,"ftp mget remote_files F",s,0);
7407 skipthis = 0; /* File selection... */
7409 nam = s; /* Filename (without path) */
7410 rc = 0; /* Initial return code */
7413 if (!getone && !skipthis) { /* For MGET and MDELETE... */
7419 debug(F111,"ftp mget havetype",s,havetype);
7420 if (havetype > 0 && havetype != FTYP_FILE) {
7421 /* Server says it's not file... */
7422 debug(F110,"ftp mget not-a-file",s,0);
7426 Explanation: Some ftp servers (such as wu-ftpd) return a recursive list.
7427 But if the client did not ask for a recursive list, we have to ignore any
7428 server files that include a pathname that extends beyond any path that
7429 was included in the user's request.
7431 User's filespec is blah or path/blah (or other non-UNIX syntax). We need to
7432 get the user's path segment. Then, for each incoming file, if it begins
7433 with the same path segment, we must strip it (point past it).
7435 src = mgetlist[mgetx]; /* In case it moved! */
7437 for (i = 0; src[i]; i++) { /* Find rightmost path separator */
7438 if (ispathsep(src[i])) /* in user's pathname */
7444 usrpath = k; /* User path segment length */
7445 debug(F111,"ftp get usrpath",src,usrpath);
7447 p = s; /* Server filename */
7448 while ((c = *p++)) { /* Look for path in server filename */
7451 nam = p; /* Pathless name (for ckmatch) */
7452 srvpath = p - s; /* Server path segment length */
7455 debug(F111,"ftp get srvpath",s,srvpath);
7459 Here we handle the case where the user said "mget foo" where foo is a
7460 directory name, and the server is sending back names like "foo/file1",
7461 "foo/file2", etc. This is a nasty trick but it's necessary because the
7462 user can't compensate by typing "mget foo/" because then the server is
7463 likely to send back "foo//file1, foo//file2" etc, and we still won't
7466 int srclen = 0, srvlen = 0;
7467 if (src) srclen = strlen(src);
7468 if (s) srvlen = strlen(s);
7469 if (src && (srvlen > srclen)) {
7470 if (!strncmp(src,s,srclen) && ispathsep(s[srclen])) {
7471 char * tmpsrc = NULL;
7472 tmpsrc = (char *)malloc(srclen + 2);
7473 strncpy(tmpsrc,src,srclen);
7474 tmpsrc[srclen] = s[srclen];
7475 tmpsrc[srclen+1] = NUL;
7476 free(mgetlist[mgetx]);
7477 mgetlist[mgetx] = tmpsrc;
7479 src = mgetlist[mgetx];
7485 If as-name not given and server filename includes path that matches
7486 the pathname from the user's file specification, we must trim the common
7487 path prefix from the server's name when constructing the local name.
7489 if (src && /* Wed Sep 25 17:27:48 2002 */
7491 !recursive && /* Thu Sep 19 16:11:59 2002 */
7493 !strncmp(src,s,usrpath)) {
7494 s2 = s + usrpath; /* Local name skips past remote path */
7497 /* This doesn't work if the path prefix contains wildcards! */
7498 haspath = (srvpath > usrpath);
7500 { /* Count path segments instead */
7503 for (p = s; *p; p++)
7504 if (ispathsep(*p)) x1++;
7505 for (p = src; *p; p++) {
7506 if (ispathsep(*p)) x2++;
7508 haspath = recursive ? x1 || x2 : x1 > x2;
7509 debug(F111,"ftp get server path segments",s,x1);
7510 debug(F111,"ftp get user path segments",src,x2);
7513 #endif /* COMMENT */
7514 debug(F111,"ftp get haspath",s+usrpath,haspath);
7516 if (haspath) { /* Server file has path segments? */
7517 if (!recursive) { /* [M]GET /RECURSIVE? */
7519 We did not ask for a recursive listing, but the server is sending us one
7520 anyway (as wu-ftpd is wont to do). We get here if the current filename
7521 includes a path segment beyond any path segment we asked for in our
7522 non-recursive [M]GET command. We MUST skip this file.
7524 debug(F111,"ftp get skipping because of path",s,0);
7528 } else if (getone && !skipthis) { /* GET (not MGET) */
7530 while ((c = *p++)) { /* Handle path in local name */
7532 if (recursive) { /* If recursive, keep it */
7535 } else { /* Otherwise lose it. */
7542 if (!*nam) /* Name without path */
7545 if (!skipthis && pv[SND_NOD].ival > 0) { /* /NODOTFILES */
7549 if (!skipthis && rcvexcept[0]) { /* /EXCEPT: list */
7551 for (i = 0; i < NSNDEXCEPT; i++) {
7552 if (!rcvexcept[i]) {
7555 xx = ckmatch(rcvexcept[i], nam, servertype == SYS_UNIX, 1);
7556 debug(F111,"ftp mget /except match",rcvexcept[i],xx);
7558 tlog(F100," refused: exception list","",0);
7559 msg = "Refused: Exception List";
7565 if (!skipthis && pv[SND_NOB].ival > 0) { /* /NOBACKUPFILES */
7571 #endif /* CKREGEX */
7575 if (!x_xla) { /* If translation is off */
7576 x_csl = -2; /* unset the charsets */
7579 ckstrncpy(filnam,s,CKMAXPATH); /* For \v(filename) */
7580 if (!*s2) /* Local name */
7581 s2 = asnambuf; /* As-name */
7583 if (!*s2) /* Sat Nov 16 19:19:39 2002 */
7584 s2 = recursive ? s : nam; /* Fri Jan 10 13:15:19 2003 */
7586 debug(F110,"ftp get filnam ",s,0);
7587 debug(F110,"ftp get asname A",s2,0);
7589 /* Receiving to real file */
7593 #endif /* PIPESEND */
7596 /* Do this here so we can decide whether to skip */
7597 if (cmd_quoting && !skipthis && asnambuf[0]) {
7601 zzstring(asnambuf,&p,&n);
7603 debug(F111,"ftp get asname B",s2,updating);
7607 local = *s2 ? s2 : s;
7609 if (!skipthis && x_fnc == XYFX_D) { /* File Collision = Discard */
7612 debug(F111,"ftp get DISCARD zchki",local,x);
7615 debug(F110,"ftp get skip name",local,0);
7616 tlog(F100," refused: name","",0);
7617 msg = "Refused: Name";
7622 if (!skipthis && updating) { /* If updating and not yet skipping */
7623 if (zchki(local) > -1) {
7624 x = chkmodtime(local,s,0);
7628 debug(F111,"ftp get /dates-diff chkmodtime",local,x);
7630 debug(F111,"ftp get /update chkmodtime",local,x);
7633 if ((updating == 1 && x > 0) || /* /UPDATE */
7634 (updating == 2 && x == 1)) { /* /DATES-DIFFER */
7636 tlog(F100," refused: date","",0);
7637 msg = "Refused: Date";
7638 debug(F110,"ftp get skip date",local,0);
7642 #endif /* DOUPDATE */
7644 /* Initialize file size to -1 in case server doesn't understand */
7645 /* SIZE command, so xxscreen() will know we don't know the size */
7647 fsize = (CK_OFF_T)-1;
7649 /* Ask for size now only if we need it for selection */
7650 /* because if you're going thru a list 100,000 files to select */
7651 /* a small subset, 100,000 SIZE commands can take hours... */
7654 if (!mdel && !skipthis && /* Don't need size for DELE... */
7655 (getsmaller >= (CK_OFF_T)0 || getlarger >= (CK_OFF_T)0)) {
7656 if (havesize >= (CK_OFF_T)0) { /* Already have file size? */
7659 } else { /* No - must ask server */
7661 Prior to sending the NLST command we necessarily put the
7662 server into ASCII mode. We must now put it back into the
7663 the requested mode so the upcoming SIZE command returns
7664 right kind of size; this is especially important for
7665 GET /RECOVER; otherwise the server returns the "ASCII" size
7666 of the file, rather than its true size.
7668 changetype(ftp_typ,0); /* Change to requested type */
7669 fsize = (CK_OFF_T)-1;
7671 x = ftpcmd("SIZE",s,x_csl,x_csr,ftp_vbm);
7672 if (x == REPLY_COMPLETE) {
7673 fsize = ckatofs(&ftp_reply_str[4]);
7679 if (getsmaller >= (CK_OFF_T)0 && fsize >= getsmaller)
7681 if (getlarger >= (CK_OFF_T)0 && fsize <= getlarger)
7684 debug(F111,"ftp get skip size",s,fsize);
7685 tlog(F100," refused: size","",0);
7686 msg = "Refused: Size";
7689 } else if (getone) {
7690 /* SIZE can fail for many reasons. Does the file exist? */
7691 x = ftpcmd("NLST",s,x_csl,x_csr,ftp_vbm);
7692 if (x != REPLY_COMPLETE) {
7693 printf(">>> FILE NOT FOUND: %s\n",s);
7696 #endif /* COMMENT */
7699 if (skipthis) { /* Skipping this file? */
7700 ftscreen(SCR_FN,'F',(CK_OFF_T)0,s);
7702 ftscreen(SCR_ST,ST_ERR,(CK_OFF_T)0,msg);
7704 ftscreen(SCR_ST,ST_SKIP,(CK_OFF_T)0,s);
7707 if (fp_nml) { /* /NAMELIST only - no transfer */
7708 fprintf(fp_nml,"%s\n",s);
7711 if (recursive && haspath && !pipesend
7714 #endif /* PIPESEND */
7721 x = zmkdir(s); /* Try to make the directory */
7722 #endif /* NOMKDIR */
7725 rc = -1; /* Failure is fatal */
7728 ftscreen(SCR_EM,0,(CK_OFF_T)0,
7729 "Directory creation failure");
7737 selected++; /* Count this file as selected */
7740 if (!gotsize && !mdel) { /* Didn't get size yet */
7741 if (havesize > (CK_OFF_T)-1) { /* Already have file size? */
7744 } else { /* No - must ask server */
7745 fsize = (CK_OFF_T)-1;
7747 x = ftpcmd("SIZE",s,x_csl,x_csr,ftp_vbm);
7748 if (x == REPLY_COMPLETE) {
7749 fsize = ckatofs(&ftp_reply_str[4]);
7755 if (mdel) { /* [M]DELETE */
7756 if (displa && !ftp_vbm)
7759 (ftpcmd("DELE",s,x_csl,x_csr,ftp_vbm) == REPLY_COMPLETE) ? 1 : -1;
7761 tlog(F110,"ftp mdelete",s,0);
7762 if (displa && !ftp_vbm)
7765 tlog(F110,"ftp mdelete failed:",s,0);
7771 } else if (rcvfilter) { /* [M]GET with filter */
7774 p = tmpbuf; /* Safe - no asname with filter */
7775 zzstring(rcvfilter,&p,&n);
7778 debug(F111,"ftp get rcvfilter",pn,n);
7779 #endif /* PIPESEND */
7781 if (toscreen) s2 = "-";
7782 } else if (pipesend) { /* [M]GET /COMMAND */
7785 p = tmpbuf; /* Safe - no asname with filter */
7786 zzstring(pipename,&p,&n);
7789 debug(F111,"ftp get pipename",pipename,n);
7790 if (toscreen) s2 = "-";
7791 } else { /* [M]GET with no pipes or filters */
7792 debug(F111,"ftp get s2 A",s2,x_cnv);
7794 s2 = "-"; /* (hokey convention for stdout) */
7795 } else if (!*s2) { /* No asname? */
7796 if (x_cnv) { /* If converting */
7797 nzrtol(s,tmpbuf,x_cnv,1,CKMAXPATH); /* convert */
7799 debug(F110,"ftp get nzrtol",s2,0);
7800 } else /* otherwise */
7801 s2 = s; /* use incoming file's name */
7803 debug(F110,"ftp get s2 B",s2,0);
7805 /* If local file already exists, take collision action */
7810 #endif /* PIPESEND */
7814 debug(F111,"ftp get zchki",s2,x);
7815 debug(F111,"ftp get x_fnc",s2,x_fnc);
7817 if (x > (CK_OFF_T)-1 && !restart) {
7819 char * newname = NULL;
7822 case XYFX_A: /* Append */
7825 case XYFX_R: /* Rename */
7826 case XYFX_B: /* Backup */
7827 znewn(s2,&newname); /* Make unique name */
7828 debug(F110,"ftp get znewn",newname,0);
7829 if (x_fnc == XYFX_B) { /* Backup existing file */
7830 x = zrename(s2,newname);
7831 debug(F111,"ftp get backup zrename",newname,x);
7832 } else { /* Rename incoming file */
7833 x = ckstrncpy(tmpbuf,newname,CKMAXPATH+1);
7835 debug(F111,"ftp get rename incoming",newname,x);
7838 ftscreen(SCR_EM,0,(CK_OFF_T)0,
7839 "Backup/Rename failed");
7844 case XYFX_D: /* Discard (already handled above) */
7845 case XYFX_U: /* Update (ditto) */
7846 case XYFX_M: /* Update (ditto) */
7847 case XYFX_X: /* Overwrite */
7855 debug(F111,"ftp get pn",pn,rcvfilter ? 1 : 0);
7856 #endif /* PIPESEND */
7857 if (pipesend && !toscreen)
7861 debug(F101,"ftp get x_xla","",x_xla);
7862 debug(F101,"ftp get x_csl","",x_csl);
7863 debug(F101,"ftp get x_csr","",x_csr);
7864 debug(F101,"ftp get append","",append);
7868 rc = getfile(s,s2,restart,append,pn,x_xla,x_csl,x_csr);
7872 debug(F111,"ftp get rc",s,rc);
7873 debug(F111,"ftp get ftp_timed_out",s,ftp_timed_out);
7874 debug(F111,"ftp get cancelfile",s,cancelfile);
7875 debug(F111,"ftp get cancelgroup",s,cancelgroup);
7876 debug(F111,"ftp get renaming",s,renaming);
7877 debug(F111,"ftp get moving",s,moving);
7885 if (deleting) { /* GET /DELETE (source file) */
7887 (ftpcmd("DELE",s,x_csl,x_csr,ftp_vbm) == REPLY_COMPLETE)
7889 tlog(F110, (rc > -1) ?
7890 " deleted" : " failed to delete", s, 0);
7892 if (renaming && rcv_rename && !toscreen) {
7893 char *p; /* Rename downloaded file */
7895 char tmpbuf[CKMAXPATH+1];
7899 debug(F111,"ftp get /rename",rcv_rename,0);
7900 zzstring(rcv_rename,&p,&n);
7901 debug(F111,"ftp get /rename",rcv_rename,0);
7906 rc = (zrename(s2,p) < 0) ? -1 : 1;
7907 debug(F111,"doftpget /RENAME zrename",p,rc);
7908 tlog(F110, (rc > -1) ?
7910 " failed to rename to",
7914 } else if (moving && rcv_move && !toscreen) {
7915 char *p; /* Move downloaded file */
7917 char tmpbuf[CKMAXPATH+1];
7921 debug(F111,"ftp get /move-to",rcv_move,0);
7922 zzstring(rcv_move,&p,&n);
7927 debug(F111,"ftp get /move-to",p,0);
7928 rc = (zrename(s2,p) < 0) ? -1 : 1;
7929 debug(F111,"doftpget /MOVE zrename",p,rc);
7930 tlog(F110, (rc > -1) ?
7931 " moved to" : " failed to move to", p, 0);
7933 if (pv[SND_SRN].ival > 0 && pv[SND_SRN].sval) {
7934 char * s = pv[SND_SRN].sval;
7935 char * srvrn = pv[SND_SRN].sval;
7936 char tmpbuf[CKMAXPATH+1];
7938 int y; /* Pass it thru the evaluator */
7939 extern int cmd_quoting; /* for \v(filename) */
7940 debug(F111,"ftp get srv_renam",s,1);
7945 zzstring(srvrn,&s,&y);
7949 debug(F111,"ftp get srv_renam",s,1);
7952 x = ftp_rename(s2,s);
7953 debug(F111,"ftp get ftp_rename",s2,x);
7954 tlog(F110, (x > 0) ?
7955 " renamed source file to" :
7956 " failed to rename source file to",
7971 debug(F101,"ftp get ftp_timed_out","",ftp_timed_out);
7972 if (ftp_timed_out) {
7974 ftscreen(SCR_EM,0,(CK_OFF_T)0,"GET timed out");
7976 #endif /* FTP_TIMEOUT */
7979 ftscreen(SCR_EM,0,(CK_OFF_T)0,"Fatal download error");
7986 debug(F101,"ftp get status","",status);
7987 debug(F101,"ftp get cancelgroup","",cancelgroup);
7988 debug(F101,"ftp get cancelfile","",cancelfile);
7989 debug(F101,"ftp get selected","",selected);
7990 debug(F101,"ftp get good","",good);
7994 if (selected == 0) { /* No files met selection criteria */
7995 status = 1; /* which is a kind of success. */
7996 } else if (status > 0) { /* Some files were selected */
7997 if (cancelgroup) /* but MGET was canceled */
7998 status = 0; /* so MGET failed */
7999 else if (cancelfile && good < 1) /* If file was canceled */
8000 status = 0; /* MGET failed if it got no files */
8004 debug(F101,"ftp get success","",success);
8007 pipesend = pipesave; /* Restore global pipe selection */
8008 if (fp_nml) { /* Close /NAMELIST */
8009 if (fp_nml != stdout)
8018 #endif /* COMMENT */
8019 ) { /* Download successful */
8021 t1 = gmstimer(); /* End time */
8022 sec = (CKFLOAT)((CKFLOAT)(t1 - t0) / 1000.0); /* Stats */
8023 if (!sec) sec = 0.001;
8026 sec = (t1 - t0) / 1000;
8028 #endif /* GFTIMER */
8029 tfcps = (long) (tfc / sec);
8031 lastxfer = W_FTP|W_RECV;
8035 ftscreen(success > 0 ? SCR_TC : SCR_CW, 0, (CK_OFF_T)0, "");
8037 if (f_tmpdir) { /* If we changed to download dir */
8038 zchdir((char *) savdir); /* Go back where we came from */
8041 #endif /* CK_TMPDIR */
8043 for (i = 0; i <= SND_MAX; i++) { /* Free malloc'd memory */
8047 for (i = 0; i < mgetn; i++) /* MGET list too */
8048 makestr(&(mgetlist[i]),NULL);
8050 if (cancelgroup) /* Clear temp-file stack */
8053 ftreset(); /* Undo switch effects */
8058 static struct keytab ftprmt[] = {
8060 { "cdup", XZCDU, 0 },
8061 { "cwd", XZCWD, CM_INV },
8062 { "delete", XZDEL, 0 },
8063 { "directory", XZDIR, 0 },
8064 { "exit", XZXIT, 0 },
8065 { "help", XZHLP, 0 },
8066 { "login", XZLGI, 0 },
8067 { "logout", XZLGO, 0 },
8068 { "mkdir", XZMKD, 0 },
8069 { "pwd", XZPWD, 0 },
8070 { "rename", XZREN, 0 },
8071 { "rmdir", XZRMD, 0 },
8072 { "type", XZTYP, 0 },
8075 static int nftprmt = (sizeof(ftprmt) / sizeof(struct keytab)) - 1;
8078 doftpsite() { /* Send a SITE command */
8081 int lcs = -1, rcs = -1;
8082 int save_vbm = ftp_vbm;
8087 if (lcs < 0) lcs = fcharset;
8089 if (rcs < 0) rcs = ftp_csr;
8091 #endif /* NOCSETS */
8092 if ((x = cmtxt("Command", "", &s, xxstring)) < 0)
8095 ckstrncpy(line,s,LINBUFSIZ);
8096 if (testing) printf(" ftp site \"%s\"...\n",line);
8098 ftp_vbm = !ckstrcmp("HELP",line,4,0);
8099 if ((reply = ftpcmd("SITE",line,lcs,rcs,ftp_vbm)) == REPLY_PRELIM) {
8101 reply = getreply(0,lcs,rcs,ftp_vbm,0);
8102 } while (reply == REPLY_PRELIM);
8105 return(success = (reply == REPLY_COMPLETE));
8110 dosetftppsv() { /* Passive mode */
8111 x = seton(&ftp_psv);
8112 if (x > 0) passivemode = ftp_psv;
8116 /* d o f t p r m t -- Parse and execute REMOTE commands */
8119 doftprmt(cx,who) int cx, who; { /* who == 1 for ftp, 0 for kermit */
8120 /* cx == 0 means REMOTE */
8121 /* cx != 0 is a XZxxx value */
8128 if ((x = cmkey(ftprmt,nftprmt,"","",xxstring)) < 0)
8133 case XZCDU: /* CDUP */
8134 if ((x = cmcfm()) < 0) return(x);
8135 return(doftpcdup());
8137 case XZCWD: /* RCD */
8138 if ((x = cmtxt("Remote directory", "", &s, xxstring)) < 0)
8140 ckstrncpy(line,s,LINBUFSIZ);
8142 return(doftpcwd(s,1));
8143 case XZPWD: /* RPWD */
8145 case XZDEL: /* RDEL */
8146 return(doftpget(FTP_MDE,1));
8147 case XZDIR: /* RDIR */
8148 return(doftpdir(FTP_DIR));
8149 case XZHLP: /* RHELP */
8150 return(doftpxhlp());
8151 case XZMKD: /* RMKDIR */
8153 case XZREN: /* RRENAME */
8155 case XZRMD: /* RRMDIR */
8157 case XZLGO: /* LOGOUT */
8159 case XZXIT: /* EXIT */
8162 printf("?Not usable with FTP - \"%s\"\n", atmbuf);
8167 doxftp() { /* Command parser for built-in FTP */
8172 int lcs = -1, rcs = -1;
8177 if (lcs < 0) lcs = fcharset;
8179 if (rcs < 0) rcs = ftp_csr;
8181 #endif /* NOCSETS */
8183 if (inserver) /* FTP not allowed in IKSD. */
8186 if (g_ftp_typ > -1) { /* Restore TYPE if saved */
8187 ftp_typ = g_ftp_typ;
8188 /* g_ftp_typ = -1; */
8192 We'll set the collision action locally in doftpget() based on whether
8193 ftp_fnc was ever set to a value. if not, we'll use the fncact value.
8195 if (ftp_fnc < 0) /* Inherit global collision action */
8196 ftp_fnc = fncact; /* if none specified for FTP */
8197 #endif /* COMMENT */
8199 /* Restore global verbose mode */
8207 ftp_dates &= 1; /* Undo any previous /UPDATE switch */
8209 dpyactive = 0; /* Reset global transfer-active flag */
8210 printlines = 0; /* Reset printlines */
8212 if (fp_nml) { /* Reset /NAMELIST */
8213 if (fp_nml != stdout)
8217 makestr(&ftp_nml,NULL);
8219 cmfdbi(&kw, /* First FDB - commands */
8221 "Hostname; or FTP command", /* help */
8223 "", /* addtl string data */
8224 nftpcmd, /* addtl numeric data 1: tbl size */
8225 0, /* addtl numeric data 2: none */
8226 xxstring, /* Processing function */
8227 ftpcmdtab, /* Keyword table */
8228 &fl /* Pointer to next FDB */
8230 cmfdbi(&fl, /* A host name or address */
8232 "Hostname or address", /* help */
8234 "", /* addtl string data */
8235 0, /* addtl numeric data 1 */
8236 0, /* addtl numeric data 2 */
8241 x = cmfdb(&kw); /* Parse a hostname or a keyword */
8243 printf("?ftp what? \"help ftp\" for hints\n");
8248 if (cmresult.fcode == _CMFLD) { /* If hostname */
8249 return(openftp(cmresult.sresult,0)); /* go open the connection */
8251 cx = cmresult.nresult;
8254 case FTP_ACC: /* ACCOUNT */
8255 if ((x = cmtxt("Remote account", "", &s, xxstring)) < 0)
8258 makestr(&ftp_acc,s);
8260 printf(" ftp account: \"%s\"\n",ftp_acc);
8261 success = (ftpcmd("ACCT",ftp_acc,-1,-1,ftp_vbm) == REPLY_COMPLETE);
8264 case FTP_GUP: /* Go UP */
8265 if ((x = cmcfm()) < 0) return(x);
8267 if (testing) printf(" ftp cd: \"(up)\"\n");
8268 return(success = doftpcdup());
8270 case FTP_CWD: /* CD */
8271 if ((x = cmtxt("Remote directory", "", &s, xxstring)) < 0)
8274 ckstrncpy(line,s,LINBUFSIZ);
8276 printf(" ftp cd: \"%s\"\n", line);
8277 return(success = doftpcwd(line,1));
8279 case FTP_CHM: /* CHMOD */
8280 if ((x = cmfld("Permissions or protection code","",&s,xxstring)) < 0)
8282 ckstrncpy(tmpbuf,s,TMPBUFSIZ);
8283 if ((x = cmtxt("Remote filename", "", &s, xxstring)) < 0)
8286 ckmakmsg(ftpcmdbuf,FTP_BUFSIZ,tmpbuf," ",s,NULL);
8288 printf(" ftp chmod: %s\n",ftpcmdbuf);
8290 (ftpcmd("SITE CHMOD",ftpcmdbuf,lcs,rcs,ftp_vbm) == REPLY_COMPLETE);
8293 case FTP_CLS: /* CLOSE FTP connection */
8294 if ((y = cmcfm()) < 0)
8298 printf(" ftp closing...\n");
8300 return(success = 1);
8302 case FTP_DIR: /* DIRECTORY of remote files */
8304 return(doftpdir(cx));
8306 case FTP_GET: /* GET a remote file */
8307 case FTP_RGE: /* REGET */
8308 case FTP_MGE: /* MGET */
8309 case FTP_MDE: /* MDELETE */
8310 return(doftpget(cx,1));
8312 case FTP_IDL: /* IDLE */
8313 if ((x = cmnum("Number of seconds","-1",10,&z,xxstring)) < 0)
8315 if ((y = cmcfm()) < 0)
8318 if (z < 0) { /* Display idle timeout */
8320 printf(" ftp query idle timeout...\n");
8321 success = (ftpcmd("SITE IDLE",NULL,0,0,1) == REPLY_COMPLETE);
8322 } else { /* Set idle timeout */
8324 printf(" ftp idle timeout set: %d...\n",z);
8326 (ftpcmd("SITE IDLE",ckitoa(z),0,0,1) == REPLY_COMPLETE);
8330 case FTP_MKD: /* MKDIR */
8333 case FTP_MOD: /* MODTIME */
8334 if ((x = cmtxt("Remote filename", "", &s, xxstring)) < 0)
8337 ckstrncpy(line,s,LINBUFSIZ);
8339 printf(" ftp modtime \"%s\"...\n",line);
8341 if (ftpcmd("MDTM",line,lcs,rcs,ftp_vbm) == REPLY_COMPLETE) {
8349 bzero((char *)&tmremote, sizeof(struct tm));
8351 while ((c = *s++)) {
8358 if (sscanf(s, "%04d%02d%02d%02d%02d%02d",
8366 printf(" %s %04d-%02d-%02d %02d:%02d:%02d GMT\n",
8383 case FTP_OPN: /* OPEN connection */
8385 x = cmfld("IP hostname or address","",&s,xxstring);
8390 ckstrncpy(line,s,LINBUFSIZ);
8392 return(openftp(s,0));
8394 { /* OPEN connection */
8395 char name[TTNAMLEN+1], *p;
8397 extern char ttname[];
8398 if (network) /* If we have a current connection */
8399 ckstrncpy(name,ttname,LINBUFSIZ); /* get the host name */
8401 *name = '\0'; /* as default host */
8402 for (p = name; *p; p++) /* Remove ":service" from end. */
8403 if (*p == ':') { *p = '\0'; break; }
8405 x = cmfld("IP hostname or address",name,&s,xxstring);
8407 cmfdbi(&kw, /* First FDB - commands */
8409 "Hostname or switch", /* help */
8411 "", /* addtl string data */
8412 ntlstab, /* addtl numeric data 1: tbl size */
8413 0, /* addtl numeric data 2: none */
8414 xxstring, /* Processing function */
8415 tlstab, /* Keyword table */
8416 &fl /* Pointer to next FDB */
8418 cmfdbi(&fl, /* A host name or address */
8420 "Hostname or address", /* help */
8422 "", /* addtl string data */
8423 0, /* addtl numeric data 1 */
8424 0, /* addtl numeric data 2 */
8431 x = cmfdb(&kw); /* Parse a hostname or a keyword */
8433 printf("?ftp open what? \"help ftp\" for hints\n");
8438 if (cmresult.fcode == _CMFLD) { /* Hostname */
8439 s = cmresult.sresult;
8441 } else if (cmresult.nresult == OPN_TLS) {
8445 #endif /* USETLSTAB */
8450 ckstrncpy(line,s,LINBUFSIZ);
8452 return(openftp(s,usetls));
8454 #endif /* COMMENT */
8456 case FTP_PUT: /* PUT */
8457 case FTP_MPU: /* MPUT */
8458 case FTP_APP: /* APPEND */
8459 case FTP_REP: /* REPUT */
8460 return(doftpput(cx,1));
8462 case FTP_PWD: /* PWD */
8464 if (x > -1) success = x;
8467 case FTP_REN: /* RENAME */
8470 case FTP_RES: /* RESET */
8473 case FTP_HLP: /* (remote) HELP */
8474 return(doftpxhlp());
8476 case FTP_RMD: /* RMDIR */
8479 case FTP_STA: /* STATUS */
8480 if ((x = cmtxt("Command", "", &s, xxstring)) < 0)
8483 ckstrncpy(line,s,LINBUFSIZ);
8484 if (testing) printf(" ftp status \"%s\"...\n",line);
8485 success = (ftpcmd("STAT",line,lcs,rcs,1) == REPLY_COMPLETE);
8488 case FTP_SIT: { /* SITE */
8489 return(doftpsite());
8492 case FTP_SIZ: /* (ask for) SIZE */
8493 if ((x = cmtxt("Remote filename", "", &s, xxstring)) < 0)
8496 ckstrncpy(line,s,LINBUFSIZ);
8498 printf(" ftp size \"%s\"...\n",line);
8499 success = (ftpcmd("SIZE",line,lcs,rcs,1) == REPLY_COMPLETE);
8504 case FTP_SYS: /* Ask for server's SYSTEM type */
8505 if ((x = cmcfm()) < 0) return(x);
8508 printf(" ftp system...\n");
8509 success = (ftpcmd("SYST",NULL,0,0,1) == REPLY_COMPLETE);
8512 case FTP_UMA: /* Set/query UMASK */
8513 if ((x = cmfld("Umask to set or nothing to query","",&s,xxstring)) < 0)
8516 ckstrncpy(tmpbuf,s,TMPBUFSIZ);
8517 if ((x = cmcfm()) < 0) return(x);
8521 printf(" ftp umask \"%s\"...\n",tmpbuf);
8523 printf(" ftp query umask...\n");
8525 success = ftp_umask(tmpbuf);
8532 if ((x = cmtxt("FTP protocol command", "", &s, xxstring)) < 0)
8535 success = (ftpcmd(s,NULL,0,0,ftp_vbm) == REPLY_COMPLETE);
8538 case FTP_TYP: /* Type */
8539 if ((x = cmkey(ftptyp,nftptyp,"","",xxstring)) < 0)
8541 if ((y = cmcfm()) < 0) return(y);
8545 tenex = (ftp_typ == FTT_TEN);
8546 changetype(ftp_typ,ftp_vbm);
8549 case FTP_CHK: /* Check if remote file(s) exist(s) */
8550 if ((x = cmtxt("remote filename", "", &s, xxstring)) < 0)
8553 success = remote_files(1,(CHAR *)s,(CHAR *)s,0) ? 1 : 0;
8556 case FTP_FEA: /* RFC2389 */
8557 if ((y = cmcfm()) < 0)
8560 success = (ftpcmd("FEAT",NULL,0,0,1) == REPLY_COMPLETE);
8562 if (sfttab[0] > 0) {
8563 ftp_aut = sfttab[SFT_AUTH];
8564 sizeok = sfttab[SFT_SIZE];
8565 mdtmok = sfttab[SFT_MDTM];
8566 mlstok = sfttab[SFT_MLST];
8571 case FTP_OPT: /* RFC2389 */
8572 /* Perhaps this should be a keyword list... */
8573 if ((x = cmfld("FTP command","",&s,xxstring)) < 0)
8576 ckstrncpy(line,s,LINBUFSIZ);
8577 if ((x = cmtxt("Options for this command", "", &s, xxstring)) < 0)
8579 success = (ftpcmd("OPTS",line,lcs,rcs,ftp_vbm) == REPLY_COMPLETE);
8582 case FTP_ENA: /* FTP ENABLE */
8583 case FTP_DIS: /* FTP DISABLE */
8584 if ((x = cmkey(ftpenatab,nftpena,"","",xxstring)) < 0)
8586 if ((y = cmcfm()) < 0) return(y);
8588 case ENA_AUTH: /* OK to use autoauthentication */
8589 ftp_aut = (cx == FTP_ENA) ? 1 : 0;
8590 sfttab[SFT_AUTH] = ftp_aut;
8592 case ENA_FEAT: /* OK to send FEAT command */
8593 featok = (cx == FTP_ENA) ? 1 : 0;
8595 case ENA_MLST: /* OK to use MLST/MLSD */
8596 mlstok = (cx == FTP_ENA) ? 1 : 0;
8597 sfttab[SFT_MLST] = mlstok;
8599 case ENA_MDTM: /* OK to use MDTM */
8600 mdtmok = (cx == FTP_ENA) ? 1 : 0;
8601 sfttab[SFT_MDTM] = mdtmok;
8603 case ENA_SIZE: /* OK to use SIZE */
8604 sizeok = (cx == FTP_ENA) ? 1 : 0;
8605 sfttab[SFT_SIZE] = sizeok;
8608 return(success = 1);
8617 case FPL_CLR: return("clear");
8618 case FPL_PRV: return("private");
8619 case FPL_SAF: return("safe");
8620 case 0: return("(not set)");
8621 default: return("(unknown)");
8626 shoftp(brief) int brief; {
8630 if (g_ftp_typ > -1) { /* Restore TYPE if saved */
8631 ftp_typ = g_ftp_typ;
8632 /* g_ftp_typ = -1; */
8635 printf("FTP connection: %s\n",connected ?
8642 printf("FTP server type: %s\n",
8643 ftp_srvtyp[0] ? ftp_srvtyp : "(unknown)");
8646 printf("Logged in as: %s\n",
8647 strval(ftp_logname,"(unknown)"));
8649 printf("Not logged in\n");
8651 if (brief) return(0);
8653 printf("\nSET FTP values:\n\n");
8656 printf(" ftp anonymous-password: %s\n",
8657 ftp_apw ? ftp_apw : "(default)"
8659 printf(" ftp auto-login: %s\n",showoff(ftp_log));
8660 printf(" ftp auto-authentication: %s\n",showoff(ftp_aut));
8662 case FTT_ASC: s = "text"; break;
8663 case FTT_BIN: s = "binary"; break;
8664 case FTT_TEN: s = "tenex"; break;
8667 printf(" ftp timeout: %ld\n",ftp_timeout);
8668 #endif /* FTP_TIMEOUT */
8669 printf(" ftp type: %s\n",s);
8670 printf(" ftp get-filetype-switching: %s\n",showoff(get_auto));
8671 printf(" ftp dates: %s\n",showoff(ftp_dates));
8672 printf(" ftp error-action: %s\n",ftp_err ? "quit":"proceed");
8673 printf(" ftp filenames: %s\n",
8674 ftp_cnv == CNV_AUTO ? "auto" : (ftp_cnv ? "converted" : "literal")
8676 printf(" ftp debug %s\n",showoff(ftp_deb));
8678 printf(" ftp passive-mode: %s\n",showoff(ftp_psv));
8679 printf(" ftp permissions: %s\n",showooa(ftp_prm));
8680 printf(" ftp verbose-mode: %s\n",showoff(ftp_vbx));
8681 printf(" ftp send-port-commands: %s\n",showoff(ftp_psv));
8682 printf(" ftp unique-server-names: %s\n",showoff(ftp_usn));
8684 /* See note in doxftp() */
8687 #endif /* COMMENT */
8688 printf(" ftp collision: %s\n",
8689 fncnam[ftp_fnc > -1 ? ftp_fnc : fncact]);
8690 printf(" ftp server-time-offset: %s\n",
8691 fts_sto ? fts_sto : "(none)");
8695 printf(" ftp character-set-translation: %s\n",showoff(ftp_xla));
8696 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8698 printf(" ftp server-character-set: %s\n",fcsinfo[ftp_csr].keyword);
8699 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8701 printf(" file character-set: %s\n",fcsinfo[fcharset].keyword);
8702 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8703 #endif /* NOCSETS */
8709 case XYFD_N: s = "none"; break;
8710 case XYFD_R: s = "serial"; break;
8711 case XYFD_C: s = "fullscreen"; break;
8712 case XYFD_S: s = "crt"; break;
8713 case XYFD_B: s = "brief"; break;
8715 printf(" ftp display: %s\n",s);
8716 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8718 if (mlstok || featok || mdtmok || sizeok || ftp_aut) {
8719 printf(" enabled: ");
8720 if (ftp_aut) printf(" AUTH");
8721 if (featok) printf(" FEAT");
8722 if (mdtmok) printf(" MDTM");
8723 if (mlstok) printf(" MLST");
8724 if (sizeok) printf(" SIZE");
8726 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8728 if (!mlstok || !featok || !mdtmok || !sizeok || !ftp_aut) {
8729 printf(" disabled: ");
8730 if (!ftp_aut) printf(" AUTH");
8731 if (!featok) printf(" FEAT");
8732 if (!mdtmok) printf(" MDTM");
8733 if (!mlstok) printf(" MLST");
8734 if (!sizeok) printf(" SIZE");
8736 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8739 case 0: s = "kermit"; break;
8740 case 1: s = "ftp"; break;
8741 case 2: s = "auto"; break;
8744 printf(" get-put-remote: %s\n",s);
8745 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8748 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8751 printf("Available security methods: ");
8754 #endif /* FTP_GSSAPI */
8756 printf("Kerberos4 ");
8757 #endif /* FTP_KRB4 */
8760 #endif /* FTP_SRP */
8763 #endif /* FTP_SSL */
8767 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8768 printf(" ftp authtype: %s\n",strval(auth_type,NULL));
8769 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8770 printf(" ftp auto-encryption: %s\n",showoff(ftp_cry));
8771 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8772 printf(" ftp credential-forwarding: %s\n",showoff(ftp_cfw));
8773 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8774 printf(" ftp command-protection-level: %s\n",shopl(ftp_cpl));
8775 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8776 printf(" ftp data-protection-level: %s\n",shopl(ftp_dpl));
8777 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8778 printf(" ftp secure proxy: %s\n",shopl(ssl_ftp_proxy));
8779 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8781 printf("Available security methods: (none)\n");
8782 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8783 #endif /* FTP_SECURITY */
8785 if (n <= cmd_rows - 3)
8792 /* FTP HELP text strings */
8794 static char * fhs_ftp[] = {
8795 "Syntax: FTP subcommand [ operands ]",
8796 " Makes an FTP connection, or sends a command to the FTP server.",
8797 " To see a list of available FTP subcommands, type \"ftp ?\".",
8798 " and then use HELP FTP xxx to get help about subcommand xxx.",
8799 " Also see HELP SET FTP, HELP SET GET-PUT-REMOTE, and HELP FIREWALL.",
8803 static char * fhs_acc[] = { /* ACCOUNT */
8804 "Syntax: FTP ACCOUNT text",
8805 " Sends an account designator to an FTP server that needs one.",
8806 " Most FTP servers do not use accounts; some use them for other",
8807 " other purposes, such as disk-access passwords.",
8810 static char * fhs_app[] = { /* APPEND */
8811 "Syntax: FTP APPEND filname",
8812 " Equivalent to [ FTP ] PUT /APPEND. See HELP FTP PUT.",
8815 static char * fhs_cls[] = { /* BYE, CLOSE */
8816 "Syntax: [ FTP ] BYE",
8817 " Logs out from the FTP server and closes the FTP connection.",
8818 " Also see HELP SET GET-PUT-REMOTE. Synonym: [ FTP ] CLOSE.",
8821 static char * fhs_cwd[] = { /* CD, CWD */
8822 "Syntax: [ FTP ] CD directory",
8823 " Asks the FTP server to change to the given directory.",
8824 " Also see HELP SET GET-PUT-REMOTE. Synonyms: [ FTP ] CWD, RCD, RCWD.",
8827 static char * fhs_gup[] = { /* CDUP, UP */
8829 " Asks the FTP server to change to the parent directory of its current",
8830 " directory. Also see HELP SET GET-PUT-REMOTE. Synonym: FTP UP.",
8833 static char * fhs_chm[] = { /* CHMOD */
8834 "Syntax: FTP CHMOD filename permissions",
8835 " Asks the FTP server to change the permissions, protection, or mode of",
8836 " the given file. The given permissions must be in the syntax of the",
8837 " the server's file system, e.g. an octal number for UNIX. Also see",
8838 " FTP PUT /PERMISSIONS",
8841 static char * fhs_mde[] = { /* DELETE */
8842 "Syntax: FTP DELETE [ switches ] filespec",
8843 " Asks the FTP server to delete the given file or files.",
8844 " Synonym: MDELETE (Kermit makes no distinction between single and",
8845 " multiple file deletion). Optional switches:",
8847 " /ERROR-ACTION:{PROCEED,QUIT}",
8849 " /FILENAMES:{AUTO,CONVERTED,LITERAL}",
8850 " /LARGER-THAN:number",
8853 #endif /* UNIXOROSK */
8856 " /RECURSIVE (depends on server)",
8858 #endif /* RECURSIVE */
8859 " /SMALLER-THAN:number",
8862 static char * fhs_dir[] = { /* DIRECTORY */
8863 "Syntax: FTP DIRECTORY [ filespec ]",
8864 " Asks the server to send a directory listing of the files that match",
8865 " the given filespec, or if none is given, all the files in its current",
8866 " directory. The filespec, including any wildcards, must be in the",
8867 " syntax of the server's file system. Also see HELP SET GET-PUT-REMOTE.",
8868 " Synonym: RDIRECTORY.",
8871 static char * fhs_vdi[] = { /* VDIRECTORY */
8872 "Syntax: FTP VDIRECTORY [ filespec ]",
8873 " Asks the server to send a directory listing of the files that match",
8874 " the given filespec, or if none is given, all the files in its current",
8875 " directory. VDIRECTORY is needed for getting verbose directory",
8876 " listings from certain FTP servers, such as on TOPS-20. Try it if",
8877 " FTP DIRECTORY lists only filenames without details.",
8880 static char * fhs_fea[] = { /* FEATURES */
8881 "Syntax: FTP FEATURES",
8882 " Asks the FTP server to list its special features. Most FTP servers",
8883 " do not recognize this command.",
8886 static char * fhs_mge[] = { /* MGET */
8887 "Syntax: [ FTP ] MGET [ options ] filespec [ filespec [ filespec ... ] ]",
8888 " Download a single file or multiple files. Asks the FTP server to send",
8889 " the given file or files. Also see FTP GET. Optional switches:",
8892 " Name under which to store incoming file.",
8893 " Pattern required for for multiple files.",
8894 " /BINARY", /* /IMAGE */
8895 " Force binary mode. Synonym: /IMAGE.",
8896 " /COLLISION:{BACKUP,RENAME,UPDATE,DISCARD,APPEND,OVERWRITE}",
8897 " What to do if an incoming file has the same name as an existing file.",
8901 " Specifies that the as-name is a command to which the incoming file",
8902 " is to be piped as standard input.",
8903 #endif /* PUTPIPE */
8907 " Download only those files whose modification date-times differ from",
8908 " those of the corresponding local files, or that do not already",
8909 " exist on the local computer.",
8910 #endif /* DOUPDATE */
8913 " Specifies that each file is to be deleted from the server after,",
8914 " and only if, it is successfully downloaded.",
8915 " /ERROR-ACTION:{PROCEED,QUIT}",
8916 " When downloading a group of files, what to do upon failure to",
8917 " transfer a file: quit or proceed to the next one.",
8919 " Exception list: don't download any files that match this pattern.",
8920 " See HELP WILDCARD for pattern syntax.",
8921 " /FILENAMES:{AUTOMATIC,CONVERTED,LITERAL}",
8922 " Whether to convert incoming filenames to local syntax.",
8926 " Pass incoming files through the given command.",
8928 #endif /* PIPESEND */
8929 " /LARGER-THAN:number",
8930 " Only download files that are larger than the given number of bytes.",
8931 " /LISTFILE:filename",
8932 " Obtain the list of files to download from the given file.",
8934 " /LOCAL-CHARACTER-SET:name",
8935 " When downloading in text mode and character-set conversion is",
8936 " desired, this specifies the target set.",
8937 #endif /* NOCSETS */
8939 " Specifies a pattern to be used to select filenames locally from the",
8942 " Forces sending of MLSD (rather than NLST) to get the file list.",
8944 " /MOVE-TO:directory",
8945 " Each file that is downloaded is to be moved to the given local",
8946 " directory immediately after, and only if, it has been received",
8948 #endif /* CK_TMPDIR */
8949 " /NAMELIST:filename",
8950 " Instead of downloading the files, stores the list of files that",
8951 " would be downloaded in the given local file, one filename per line.",
8953 " Forces sending of NLST (rather than MLSD) to get the file list.",
8955 " Don't download any files whose names end with .~<number>~.",
8957 " Don't download any files whose names begin with period (.).",
8959 " Suppress the file-transfer display.",
8961 " /RECOVER", /* /RESTART */
8962 " Resume a download that was previously interrupted from the point of",
8963 " failure. Works only in binary mode. Not supported by all servers.",
8964 " Synonym: /RESTART.",
8965 #endif /* FTP_RESTART */
8967 " /RECURSIVE", /* /SUBDIRECTORIES */
8968 " Create subdirectories automatically if the server sends files",
8969 " recursively and includes pathnames (most don't).",
8970 #endif /* RECURSIVE */
8972 " Each file that is downloaded is to be renamed as indicated just,",
8973 " after, and only if, it has arrived successfully.",
8975 " /SERVER-CHARACTER-SET:name",
8976 " When downloading in text mode and character-set conversion is desired"
8977 , " this specifies the original file's character set on the server.",
8978 #endif /* NOCSETS */
8979 " /SERVER-RENAME:text",
8980 " Each server source file is to be renamed on the server as indicated",
8981 " immediately after, but only if, it has arrived successfully.",
8982 " /SMALLER-THAN:number",
8983 " Download only those files smaller than the given number of bytes.",
8984 " /TEXT", /* /ASCII */
8985 " Force text mode. Synonym: /ASCII.",
8987 " Force TENEX (TOPS-20) mode (see HELP SET FTP TYPE).",
8990 " When downloading in text mode, do not convert chracter-sets.",
8991 #endif /* NOCSETS */
8993 " The downloaded file is to be displayed on the screen.",
8996 " Equivalent to /COLLISION:UPDATE. Download only those files that are",
8997 " newer than than their local counterparts, or that do not exist on",
8998 " the local computer.",
8999 #endif /* DOUPDATE */
9002 static char * fhs_hlp[] = { /* HELP */
9003 "Syntax: FTP HELP [ command [ subcommand... ] ]",
9004 " Asks the FTP server for help about the given command. First use",
9005 " FTP HELP by itself to get a list of commands, then use HELP FTP xxx",
9006 " to get help for command \"xxx\". Synonyms: REMOTE HELP, RHELP.",
9009 static char * fhs_idl[] = { /* IDLE */
9010 "Syntax: FTP IDLE [ number ]",
9011 " If given without a number, this asks the FTP server to tell its",
9012 " current idle-time limit. If given with a number, it asks the server",
9013 " to change its idle-time limit to the given number of seconds.",
9016 static char * fhs_usr[] = { /* USER, LOGIN */
9017 "Syntax: FTP USER username [ password [ account ] ]",
9018 " Log in to the FTP server. To be used when connected but not yet",
9019 " logged in, e.g. when SET FTP AUTOLOGIN is OFF or autologin failed.",
9020 " If you omit the password, and one is required by the server, you are",
9021 " prompted for it. If you omit the account, no account is sent.",
9022 " Synonym: FTP LOGIN.",
9025 static char * fhs_get[] = { /* GET */
9026 "Syntax: [ FTP ] GET [ options ] filename [ as-name ]",
9027 " Download a single file. Asks the FTP server to send the given file.",
9028 " The optional as-name is the name to store it under when it arrives;",
9029 " if omitted, the file is stored with the name it arrived with, as",
9030 " modified according to the FTP FILENAMES setting or /FILENAMES: switch",
9031 " value. Aside from the file list and as-name, syntax and options are",
9032 " the same as for FTP MGET, which is used for downloading multiple files."
9035 static char * fhs_mkd[] = { /* MKDIR */
9036 "Syntax: FTP MKDIR directory",
9037 " Asks the FTP server to create a directory with the given name,",
9038 " which must be in the syntax of the server's file system. Synonyms:",
9039 " REMOTE MKDIR, RMKDIR.",
9042 static char * fhs_mod[] = { /* MODTIME */
9043 "Syntax: FTP MODTIME filename",
9044 " Asks the FTP server to send the modification time of the given file,",
9045 " to be displayed on the screen. The date-time format is all numeric:",
9046 " yyyymmddhhmmssxxx... (where xxx... is 0 or more digits indicating",
9047 " fractions of seconds).",
9050 static char * fhs_mpu[] = { /* MPUT */
9051 "Syntax: [ FTP ] MPUT [ switches ] filespec [ filespec [ filespec ... ] ]",
9052 " Uploads files. Sends the given file or files to the FTP server.",
9053 " Also see FTP PUT. Optional switches are:",
9055 " /AFTER:date-time",
9056 " Uploads only those files newer than the given date-time.",
9057 " HELP DATE for info about date-time formats. Synonym: /SINCE.",
9059 " /ARRAY:array-designator",
9060 " Tells Kermit to upload the contents of the given array, rather than",
9062 #endif /* PUTARRAY */
9064 " Name under which to send files.",
9065 " Pattern required for for multiple files.",
9066 " /BEFORE:date-time",
9067 " Upload only those files older than the given date-time.",
9069 " Force binary mode. Synonym: /IMAGE.",
9072 " Specifies that the filespec is a command whose standard output is",
9074 #endif /* PUTPIPE */
9079 " Upload only those files whose modification date-times differ from",
9080 " those on the server, or that don't exist on the server at all.",
9081 #endif /* DOUPDATE */
9082 #endif /* COMMENT */
9085 " Specifies that each source file is to be deleted after, and only if,",
9086 " it is successfully uploaded.",
9088 " Include files whose names begin with period (.).",
9089 " /ERROR-ACTION:{PROCEED,QUIT}",
9090 " When uploading a group of files, what to do upon failure to",
9091 " transfer a file: quit or proceed to the next one.",
9093 " Exception list: don't upload any files that match this pattern.",
9094 " See HELP WILDCARD for pattern syntax.",
9095 " /FILENAMES:{AUTOMATIC,CONVERTED,LITERAL}",
9096 " Whether to convert outbound filenames to common syntax.",
9100 " Pass outbound files through the given command.",
9102 #endif /* PIPESEND */
9105 " Send files that are pointed to by symbolic links.",
9107 " Skip over symbolic links (default).",
9108 #endif /* CKSYMLINK */
9109 " /LARGER-THAN:number",
9110 " Only upload files that are larger than the given number of bytes.",
9111 " /LISTFILE:filename",
9112 " Obtain the list of files to upload from the given file.",
9114 " /LOCAL-CHARACTER-SET:name",
9115 " When uploading in text mode and character-set conversion is",
9116 " desired, this specifies the source-file character set.",
9117 #endif /* NOCSETS */
9119 " /MOVE-TO:directory",
9120 " Each source file that is uploaded is to be moved to the given local",
9121 " directory when, and only if, the transfer is successful.",
9122 #endif /* CK_TMPDIR */
9124 " Don't upload any files whose names end with .~<number>~.",
9127 " Don't upload any files whose names begin with period (.).",
9128 #endif /* UNIXOROSK */
9129 " /NOT-AFTER:date-time",
9130 " Upload only files that are not newer than the given date-time",
9131 " /NOT-BEFORE:date-time",
9132 " Upload only files that are not older than the given date-time",
9135 " Ask the server to set the permissions of each file it receives",
9136 " according to the source file's permissions.",
9139 " Suppress the file-transfer display.",
9142 " Resume an upload that was previously interrupted from the point of",
9143 " failure. Synonym: /RESTART.",
9144 #endif /* FTP_RESTART */
9147 " Send files from the given directory and all the directories beneath",
9148 " it. Synonym: /SUBDIRECTORIES.",
9149 #endif /* RECURSIVE */
9151 " Each source file that is uploaded is to be renamed on the local",
9152 " local computer as indicated when and only if, the transfer completes",
9155 " /SERVER-CHARACTER-SET:name",
9156 " When uploading in text mode and character-set conversion is desired,",
9157 " this specifies the character set to which the file should be",
9158 " converted for storage on the server.",
9159 #endif /* NOCSETS */
9160 " /SERVER-RENAME:text",
9161 " Each file that is uploaded is to be renamed as indicated on the",
9162 " server after, and only if, if arrives successfully.",
9164 " Show which files would be sent without actually sending them.",
9165 " /SMALLER-THAN:number",
9166 " Upload only those files smaller than the given number of bytes.",
9168 " Force text mode. Synonym: /ASCII.",
9170 " Force TENEX (TOPS-20) mode (see HELP SET FTP TYPE).",
9173 " When uploading in text mode, do not convert chracter-sets.",
9174 #endif /* NOCSETS */
9175 " /TYPE:{TEXT,BINARY}",
9176 " Upload only files of the given type.",
9179 " If a file of the same name exists on the server, upload only if",
9180 " the local file is newer.",
9181 #endif /* DOUPDATE */
9182 " /UNIQUE-SERVER-NAMES",
9183 " Ask the server to compute new names for any incoming file that has",
9184 " the same name as an existing file.",
9187 static char * fhs_opn[] = { /* OPEN */
9189 "Syntax: FTP [ OPEN ] [ { /SSL, /TLS } ] hostname [ port ] [ switches ]",
9190 " Opens a connection to the FTP server on the given host. The default",
9191 " TCP port is 21 (990 if SSL/TLS is used), but a different port number",
9192 " can be supplied if necessary. Optional switches are:",
9194 "Syntax: FTP [ OPEN ] hostname [ port ] [ switches ]",
9195 " Opens a connection to the FTP server on the given host. The default",
9196 " TCP port is 21, but a different port number can be supplied if",
9197 " necessary. Optional switches are:",
9201 " Logs you in anonymously.",
9203 " Supplies the given text as your username.",
9205 " Supplies the given text as your password. If you include a username",
9206 " but omit this switch and the server requires a password, you are",
9207 " prompted for it.",
9209 " Supplies the given text as your account, if required by the server.",
9211 " Forces an active (rather than passive) connection.",
9213 " Forces a passive (rather than active) connection.",
9215 " Inhibits sending initial REST, STRU, and MODE commands, which are",
9216 " well-known standard commands, but to which some servers react badly.",
9218 " Inhibits autologin for this connection only.",
9221 static char * fhs_opt[] = { /* OPTS, OPTIONS */
9222 "Syntax: FTP OPTIONS",
9223 " Asks the FTP server to list its current options. Advanced, new,",
9224 " not supported by most FTP servers.",
9227 static char * fhs_put[] = { /* PUT, SEND */
9228 "Syntax: [ FTP ] PUT [ switches ] filespec [ as-name ]",
9229 " Like FTP MPUT, but only one filespec is allowed, and if it is followed",
9230 " by an additional field, this is interpreted as the name under which",
9231 " to send the file or files. See HELP FTP MPUT.",
9234 static char * fhs_reput[] = { /* REPUT, RESEND */
9235 "Syntax: [ FTP ] REPUT [ switches ] filespec [ as-name ]",
9236 " Synonym for FTP PUT /RECOVER. Recovers an interrupted binary-mode",
9237 " upload from the point of failure if the FTP server supports recovery.",
9238 " Synonym: [ FTP ] RESEND. For details see HELP FTP MPUT.",
9241 static char * fhs_pwd[] = { /* PWD */
9243 " Asks the FTP server to reveal its current working directory.",
9244 " Synonyms: REMOTE PWD, RPWD.",
9247 static char * fhs_quo[] = { /* QUOTE */
9248 "Syntax: FTP QUOTE text",
9249 " Sends an FTP protocol command to the FTP server. Use this command",
9250 " for sending commands that Kermit might not support.",
9253 static char * fhs_rge[] = { /* REGET */
9254 "Syntax: FTP REGET",
9255 " Synonym for FTP GET /RECOVER.",
9258 static char * fhs_ren[] = { /* RENAME */
9259 "Syntax: FTP RENAME name1 name1",
9260 " Asks the FTP server to change the name of the file whose name is name1",
9261 " and which resides in the FTP server's file system, to name2. Works",
9262 " only for single files; wildcards are not accepted.",
9265 static char * fhs_res[] = { /* RESET */
9266 "Syntax: FTP RESET",
9267 " Asks the server to log out your session, terminating your access",
9268 " rights, without closing the connection.",
9271 static char * fhs_rmd[] = { /* RMDIR */
9272 "Syntax: FTP RMDIR directory",
9273 " Asks the FTP server to remove the directory whose name is given.",
9274 " This usually requires the directory to be empty. Synonyms: REMOTE",
9278 static char * fhs_sit[] = { /* SITE */
9279 "Syntax: FTP SITE text",
9280 " Sends a site-specific command to the FTP server.",
9283 static char * fhs_siz[] = { /* SIZE */
9284 "Syntax: FTP SIZE filename",
9285 " Asks the FTP server to send a numeric string representing the size",
9286 " of the given file.",
9289 static char * fhs_sta[] = { /* STATUS */
9290 "Syntax: FTP STATUS [ filename ]",
9291 " Asks the FTP server to report its status. If a filename is given,",
9292 " the FTP server should report details about the file.",
9295 static char * fhs_sys[] = { /* SYSTEM */
9296 "Syntax: FTP SYSTEM",
9297 " Asks the FTP server to report its operating system type.",
9300 static char * fhs_typ[] = { /* TYPE */
9301 "Syntax: FTP TYPE { TEXT, BINARY, TENEX }",
9302 " Puts the client and server in the indicated transfer mode.",
9303 " ASCII is a synonym for TEXT. TENEX is used only for uploading 8-bit",
9304 " binary files to a 36-bit platforms such as TENEX or TOPS-20 and/or",
9305 " downloading files from TENEX or TOPS-20 that have been uploaded in",
9309 static char * fhs_uma[] = { /* UMASK */
9310 "Syntax: FTP UMASK number",
9311 " Asks the FTP server to set its file creation mode mask. Applies",
9312 " only (or mainly) to UNIX-based FTP servers.",
9315 static char * fhs_chk[] = { /* CHECK */
9316 "Syntax: FTP CHECK remote-filespec",
9317 " Asks the FTP server if the given file or files exist. If the",
9318 " remote-filespec contains wildcards, this command fails if no server",
9319 " files match, and succeeds if at least one file matches. If the",
9320 " remote-filespec does not contain wildcards, this command succeeds if",
9321 " the given file exists and fails if it does not.",
9324 static char * fhs_ena[] = { /* ENABLE */
9325 "Syntax: FTP ENABLE { AUTH, FEAT, MDTM, MLST, SIZE }",
9326 " Enables the use of the given FTP protocol command in case it has been",
9327 " disabled (but this is no guarantee that the FTP server understands it)."
9329 " Use SHOW FTP to see which of these commands is enabled and disabled.",
9330 " Also see FTP DISABLE.",
9333 static char * fhs_dis[] = { /* DISABLE */
9334 "Syntax: FTP DISABLE { AUTH, FEAT, MDTM, MLST, SIZE }",
9335 " Disables the use of the given FTP protocol command.",
9336 " Also see FTP ENABLE.",
9345 if ((cx = cmkey(ftpcmdtab,nftpcmd,"","",xxstring)) < 0)
9348 if ((x = cmcfm()) < 0)
9352 printf("Sorry, no help available\n");
9356 return(hmsga(fhs_ftp));
9357 case FTP_ACC: /* ACCOUNT */
9358 return(hmsga(fhs_acc));
9359 case FTP_APP: /* APPEND */
9360 return(hmsga(fhs_app));
9361 case FTP_CLS: /* BYE, CLOSE */
9362 return(hmsga(fhs_cls));
9363 case FTP_CWD: /* CD, CWD */
9364 return(hmsga(fhs_cwd));
9365 case FTP_GUP: /* CDUP, UP */
9366 return(hmsga(fhs_gup));
9367 case FTP_CHM: /* CHMOD */
9368 return(hmsga(fhs_chm));
9369 case FTP_MDE: /* DELETE, MDELETE */
9370 return(hmsga(fhs_mde));
9371 case FTP_DIR: /* DIRECTORY */
9372 return(hmsga(fhs_dir));
9373 case FTP_VDI: /* VDIRECTORY */
9374 return(hmsga(fhs_vdi));
9375 case FTP_FEA: /* FEATURES */
9376 return(hmsga(fhs_fea));
9377 case FTP_GET: /* GET */
9378 return(hmsga(fhs_get));
9379 case FTP_HLP: /* HELP */
9380 return(hmsga(fhs_hlp));
9381 case FTP_IDL: /* IDLE */
9382 return(hmsga(fhs_idl));
9383 case FTP_USR: /* USER, LOGIN */
9384 return(hmsga(fhs_usr));
9385 case FTP_MGE: /* MGET */
9386 return(hmsga(fhs_mge));
9387 case FTP_MKD: /* MKDIR */
9388 return(hmsga(fhs_mkd));
9389 case FTP_MOD: /* MODTIME */
9390 return(hmsga(fhs_mod));
9391 case FTP_MPU: /* MPUT */
9392 return(hmsga(fhs_mpu));
9393 case FTP_OPN: /* OPEN */
9394 return(hmsga(fhs_opn));
9395 case FTP_OPT: /* OPTS, OPTIONS */
9396 return(hmsga(fhs_opt));
9397 case FTP_PUT: /* PUT, SEND */
9398 return(hmsga(fhs_put));
9399 case FTP_REP: /* REPUT, RESEND */
9400 return(hmsga(fhs_reput));
9401 case FTP_PWD: /* PWD */
9402 return(hmsga(fhs_pwd));
9403 case FTP_QUO: /* QUOTE */
9404 return(hmsga(fhs_quo));
9405 case FTP_RGE: /* REGET */
9406 return(hmsga(fhs_rge));
9407 case FTP_REN: /* RENAME */
9408 return(hmsga(fhs_ren));
9409 case FTP_RES: /* RESET */
9410 return(hmsga(fhs_res));
9411 case FTP_RMD: /* RMDIR */
9412 return(hmsga(fhs_rmd));
9413 case FTP_SIT: /* SITE */
9414 return(hmsga(fhs_sit));
9415 case FTP_SIZ: /* SIZE */
9416 return(hmsga(fhs_siz));
9417 case FTP_STA: /* STATUS */
9418 return(hmsga(fhs_sta));
9419 case FTP_SYS: /* SYSTEM */
9420 return(hmsga(fhs_sys));
9421 case FTP_TYP: /* TYPE */
9422 return(hmsga(fhs_typ));
9423 case FTP_UMA: /* UMASK */
9424 return(hmsga(fhs_uma));
9425 case FTP_CHK: /* CHECK */
9426 return(hmsga(fhs_chk));
9428 return(hmsga(fhs_ena));
9430 return(hmsga(fhs_dis));
9432 printf("Sorry, help available for this command.\n");
9436 return(success = 0);
9442 if ((cx = cmkey(ftpset,nftpset,"","",xxstring)) < 0)
9446 ckstrncpy(tmpbuf,atmbuf,TMPBUFSIZ);
9447 if ((x = cmcfm()) < 0)
9451 printf("Sorry, no help available\n");
9455 printf("\nSyntax: SET FTP parameter value\n");
9456 printf(" Type \"help set ftp ?\" for a list of parameters.\n");
9457 printf(" Type \"help set ftp xxx\" for information about setting\n");
9458 printf(" parameter xxx. Type \"show ftp\" for current values.\n\n");
9462 printf("\nSyntax: SET FTP BUG <name> {ON, OFF}\n");
9464 " Activates a workaround for the named bug in the FTP server.\n");
9465 printf(" Type SET FTP BUG ? for a list of names.\n");
9466 printf(" For each bug, the default is OFF\n\n");
9470 case FTS_ATP: /* "authtype" */
9471 printf("\nSyntax: SET FTP AUTHTYPE list\n");
9472 printf(" Specifies an ordered list of authentication methods to be\n"
9474 printf(" when FTP AUTOAUTHENTICATION is ON. The default list is:\n");
9475 printf(" GSSAPI-KRB5, SRP, KERBEROS_V4, TLS, SSL.\n\n");
9478 case FTS_AUT: /* "autoauthentication" */
9479 printf("\nSyntax:SET FTP AUTOAUTHENTICATION { ON, OFF }\n");
9480 printf(" Tells whether authentication should be negotiated by the\n");
9481 printf(" FTP OPEN command. Default is ON.\n\n");
9484 case FTS_CRY: /* "autoencryption" */
9485 printf("\nSET FTP AUTOENCRYPTION { ON, OFF }\n");
9486 printf(" Tells whether encryption (privacy) should be negotiated\n");
9487 printf(" by the FTP OPEN command. Default is ON.\n\n");
9489 #endif /* FTP_SECURITY */
9491 case FTS_LOG: /* "autologin" */
9492 printf("\nSET FTP AUTOLOGIN { ON, OFF }\n");
9493 printf(" Tells Kermit whether to try to log you in automatically\n");
9494 printf(" as part of the connection process.\n\n");
9498 printf("\nSET FTP DISPLAY { BRIEF, FULLSCREEN, CRT, ... }\n");
9499 printf(" Chooses the file-transfer display style for FTP.\n");
9500 printf(" Like SET TRANSFER DISPLAY but applies only to FTP.\n\n");
9504 case FTS_XLA: /* "character-set-translation" */
9505 printf("\nSET FTP CHARACTER-SET-TRANSLATION { ON, OFF }\n");
9506 printf(" Whether to translate character sets when transferring\n");
9507 printf(" text files with FTP. OFF by default.\n\n");
9510 #endif /* NOCSETS */
9511 case FTS_FNC: /* "collision" */
9514 "Syntax: SET FTP COLLISION { BACKUP,RENAME,UPDATE,DISCARD,APPEND,OVERWRITE }\n"
9516 printf(" Tells what do when an incoming file has the same name as\n");
9517 printf(" an existing file when downloading with FTP.\n\n");
9521 case FTS_CPL: /* "command-protection-level" */
9524 "Syntax: SET FTP COMMAND-PROTECTION-LEVEL { CLEAR,CONFIDENTIAL,PRIVATE,SAFE }"
9528 " Tells what level of protection is applied to the FTP command channel.\n\n");
9530 case FTS_CFW: /* "credential-forwarding" */
9531 printf("\nSyntax: SET FTP CREDENTIAL-FORWARDING { ON, OFF }\n");
9532 printf(" Tells whether end-user credentials are to be forwarded\n");
9533 printf(" to the server if supported by the authentication method\n");
9534 printf(" (GSSAPI-KRB5 only).\n\n");
9536 case FTS_DPL: /* "data-protection-level" */
9539 "Syntax: SET FTP DATA-PROTECTION-LEVEL { CLEAR,CONFIDENTIAL,PRIVATE,SAFE }"
9543 " Tells what level of protection is applied to the FTP data channel.\n\n");
9545 #endif /* FTP_SECURITY */
9547 case FTS_DBG: /* "debug" */
9548 printf("\nSyntax: SET FTP DEBUG { ON, OFF }\n");
9549 printf(" Whether to print FTP protocol messages.\n\n");
9552 case FTS_ERR: /* "error-action" */
9553 printf("\nSyntax: SET FTP ERROR-ACTION { QUIT, PROCEED }\n");
9554 printf(" What to do when an error occurs when transferring a group\n")
9556 printf(" of files: quit and fail, or proceed to the next file.\n\n");
9559 case FTS_CNV: /* "filenames" */
9560 printf("\nSyntax: SET FTP FILENAMES { AUTO, CONVERTED, LITERAL }\n");
9561 printf(" What to do with filenames: convert them, take and use them\n"
9563 printf(" literally; or choose what to do automatically based on the\n"
9565 printf(" OS type of the server. The default is AUTO.\n\n");
9568 case FTS_PSV: /* "passive-mode" */
9569 printf("\nSyntax: SET FTP PASSIVE-MODE { ON, OFF }\n");
9570 printf(" Whether to use passive mode, which helps to get through\n");
9571 printf(" firewalls. ON by default.\n\n");
9574 case FTS_PRM: /* "permissions" */
9575 printf("\nSyntax: SET FTP PERMISSIONS { AUTO, ON, OFF }\n");
9576 printf(" Whether to try to send file permissions when uploading.\n");
9577 printf(" OFF by default. AUTO means only if client and server\n");
9578 printf(" have the same OS type.\n\n");
9581 case FTS_TST: /* "progress-messages" */
9582 printf("\nSyntax: SET FTP PROGRESS-MESSAGES { ON, OFF }\n");
9583 printf(" Whether Kermit should print locally-generated feedback\n");
9584 printf(" messages for each non-file-transfer command.");
9585 printf(" ON by default.\n\n");
9588 case FTS_SPC: /* "send-port-commands" */
9589 printf("\nSyntax: SET FTP SEND-PORT-COMMANDS { ON, OFF }\n");
9590 printf(" Whether Kermit should send a new PORT command for each");
9591 printf(" task.\n\n");
9595 case FTS_CSR: /* "server-character-set" */
9596 printf("\nSyntax: SET FTP SERVER-CHARACTER-SET name\n");
9597 printf(" The name of the character set used for text files on the\n");
9598 printf(" server. Enter a name of '?' for a menu.\n\n");
9600 #endif /* NOCSETS */
9602 case FTS_STO: /* "server-time-offset */
9604 "\nSyntax: SET FTP SERVER-TIME-OFFSET +hh[:mm[:ss]] or -hh[:mm[:ss]]\n");
9606 " Specifies an offset to apply to the server's file timestamps.\n");
9608 " Use this to correct for misconfigured server time or timezone.\n");
9610 " Format: must begin with + or - sign. Hours must be given; minutes\n");
9612 " and seconds are optional: +4 = +4:00 = +4:00:00 (add 4 hours).\n\n");
9615 case FTS_TYP: /* "type" */
9616 printf("\nSyntax: SET FTP TYPE { TEXT, BINARY, TENEX }\n");
9617 printf(" Establishes the default transfer mode.\n");
9618 printf(" TENEX is used for uploading 8-bit binary files to 36-bit\n");
9619 printf(" platforms such as TENEX and TOPS-20 and for downloading\n");
9620 printf(" them again. ASCII is a synonym for TEXT. Normally each\n");
9621 printf(" file's type is determined automatically from its contents\n"
9623 printf(" or its name; SET FTP TYPE does not prevent that, it only\n");
9624 printf(" tells which mode to use when the type can't be determined\n"
9626 printf(" automatically. To completely disable automatic transfer-\n"
9628 printf(" mode switching and force either text or binary mode, give\n"
9630 printf(" the top-level command ASCII or BINARY, as in traditional\n");
9631 printf(" FTP clients.\n\n");
9636 printf("\nSyntax: SET FTP TIMEOUT number-of-seconds\n");
9637 printf(" Establishes a timeout for FTP transfers.\n");
9638 printf(" The timeout applies per network read or write on the data\n");
9639 printf(" connection, not to the whole transfer. By default the\n");
9640 printf(" timeout value is 0, meaning no timeout. Use a positive\n");
9641 printf(" number to escape gracefully from hung data connections or\n");
9642 printf(" directory listings.\n\n");
9644 #endif /* FTP_TIMEOUT */
9648 printf("\nSyntax: SET FTP GET-FILETYPE-SWITCHING { ON, OFF }\n");
9649 printf(" Tells whether GET and MGET should automatically switch\n");
9650 printf(" the appropriate file type, TEXT, BINARY, or TENEX, by\n");
9651 printf(" matching the name of each incoming file with its list of\n");
9652 printf(" FILE TEXT-PATTERNS and FILE BINARY-PATTERNS. ON by\n");
9653 printf(" default. SHOW PATTERNS displays the current pattern\n");
9654 printf(" list. HELP SET FILE to see how to change it.\n");
9656 #endif /* PATTERNS */
9658 case FTS_USN: /* "unique-server-names" */
9659 printf("\nSyntax: SET FTP UNIQUE-SERVER-NAMES { ON, OFF }\n");
9660 printf(" Tells whether to ask the server to create unique names\n");
9661 printf(" for any uploaded file that has the same name as an\n");
9662 printf(" existing file. Default is OFF.\n\n");
9665 case FTS_VBM: /* "verbose-mode" */
9666 printf("\nSyntax: SET FTP VERBOSE-MODE { ON, OFF }\n");
9667 printf(" Whether to display all responses from the FTP server.\n");
9668 printf(" OFF by default.\n\n");
9672 printf("\nSyntax: SET FTP DATES { ON, OFF }\n");
9673 printf(" Whether to set date of incoming files from the file date\n");
9674 printf(" on the server. ON by default. Note: there is no way to\n")
9676 printf(" set the date on files uploaded to the server. Also note\n");
9677 printf(" that not all servers support this feature.\n\n");
9681 printf("\nSyntax: SET FTP ANONYMOUS-PASSWORD [ text ]\n");
9682 printf(" Password to supply automatically on anonymous FTP\n");
9683 printf(" connections instead of the default user@host.\n");
9684 printf(" Omit optional text to restore default.\n\n");
9688 printf("Sorry, help not available for \"set ftp %s\"\n",tmpbuf);
9702 char srp_user[BUFSIZ]; /* where is BUFSIZ defined? */
9705 #endif /* FTP_SRP */
9707 static int kerror; /* Needed for all auth types */
9709 static struct sockaddr_in hisctladdr;
9710 static struct sockaddr_in hisdataaddr;
9711 static struct sockaddr_in data_addr;
9712 static int data = -1;
9713 static int ptflag = 0;
9714 static struct sockaddr_in myctladdr;
9720 #endif /* COMMENT */
9723 static int cpend = 0; /* No pending replies */
9726 extern SSL *ssl_ftp_con;
9727 extern SSL_CTX *ssl_ftp_ctx;
9728 extern SSL *ssl_ftp_data_con;
9729 extern int ssl_ftp_active_flag;
9730 extern int ssl_ftp_data_active_flag;
9733 /* f t p c m d -- Send a command to the FTP server */
9736 char * cmd: The command to send.
9737 char * arg: The argument (e.g. a filename).
9738 int lcs: The local character set index.
9739 int rcs: The remote (server) character set index.
9740 int vbm: Verbose mode:
9741 0 = force verbosity off
9742 >0 = force verbosity on
9744 If arg is given (not NULL or empty) and lcs != rcs and both are > -1,
9745 and neither lcs or rcs is UCS-2, the arg is translated from the local
9746 character set to the remote one before sending the result to the server.
9749 0 on failure with ftpcode = -1
9750 >= 0 on success (getreply() result) with ftpcode = 0.
9752 static char xcmdbuf[RFNBUFSIZ];
9755 ftpcmd(cmd,arg,lcs,rcs,vbm) char * cmd, * arg; int lcs, rcs, vbm; {
9757 int r = 0, x = 0, fc = 0, len = 0, cmdlen = 0, q = -1;
9760 if (ftp_deb) /* DEBUG */
9762 else if (quiet || dpyactive) /* QUIET or File Transfer Active */
9764 else if (vbm < 0) /* VERBOSE */
9770 cmdlen = (int)strlen(cmd);
9771 len = cmdlen + (int)strlen(arg) + 1;
9773 if (ftp_deb /* && !dpyactive */ ) {
9775 if (ftp_prx) printf("%s ", ftp_host);
9776 #endif /* FTP_PROXY */
9778 if (!anonymous && strcmp("PASS",cmd) == 0)
9779 printf("PASS XXXX");
9781 printf("%s %s",cmd,arg);
9784 /* bzero(xcmdbuf,RFNBUFSIZ); */
9785 ckmakmsg(xcmdbuf,RFNBUFSIZ, cmd, *arg ? " " : "", arg, NULL);
9789 debug(F110,"ftpcmd cmd",cmd,0);
9790 debug(F110,"ftpcmd arg",arg,0);
9791 debug(F101,"ftpcmd lcs","",lcs);
9792 debug(F101,"ftpcmd rcs","",rcs);
9796 if (csocket == -1) {
9797 perror("No control connection for command");
9802 oldintr = signal(SIGINT, cmdcancel);
9805 if (*arg && /* If an arg was given */
9806 lcs > -1 && /* and a local charset */
9807 rcs > -1 && /* and a remote charset */
9808 lcs != rcs && /* and the two are not the same */
9809 lcs != FC_UCS2 && /* and neither one is UCS-2 */
9810 rcs != FC_UCS2 /* ... */
9812 initxlate(lcs,rcs); /* Translate arg from lcs to rcs */
9813 xgnbp = arg; /* Global pointer to input string */
9814 rfnptr = rfnbuf; /* Global pointer to output buffer */
9817 if ((c0 = xgnbyte(FC_UCS2,lcs,strgetc)) < 0) break;
9818 if (xpnbyte(c0,TC_UCS2,rcs,strputc) < 0) break;
9821 We have to copy here instead of translating directly into
9822 xcmdbuf[] so strputc() can check length. Alternatively we could
9823 write yet another xpnbyte() output function.
9825 if ((int)strlen(rfnbuf) > (RFNBUFSIZ - (cmdlen+1))) {
9826 printf("?FTP command too long: %s + arg\n",cmd);
9830 x = ckstrncpy(&xcmdbuf[cmdlen+1], rfnbuf, RFNBUFSIZ - (cmdlen+1));
9832 #endif /* NOCSETS */
9834 s = xcmdbuf; /* Command to send to server */
9837 if (deblog) { /* Log it */
9838 if (!anonymous && !ckstrcmp(s,"PASS ",5,0)) {
9839 /* But don't log passwords */
9840 debug(F110,"FTP SENT ","PASS XXXX",0);
9842 debug(F110,"FTP SENT ",s,0);
9847 #ifdef CK_ENCRYPTION
9849 #endif /* CK_ENCRYPTION */
9850 if (scommand(s) == 0) { /* Send it. */
9851 signal(SIGINT, oldintr);
9855 x = !strcmp(cmd,"QUIT"); /* Is it the QUIT command? */
9856 if (x) /* In case we're interrupted */
9857 connected = 0; /* while waiting for the reply... */
9859 fc = 0; /* Function code for getreply() */
9860 if (!strncmp(cmd,"AUTH ",5) /* Must parse AUTH reply */
9862 && strncmp(cmd, "HOST ",5)
9863 #endif /* FTPHOST */
9866 } else if (!ckstrcmp(cmd,"FEAT",-1,0)) { /* Must parse FEAT reply */
9867 fc = GRF_FEAT; /* But FEAT not widely understood */
9868 if (!ftp_deb) /* So suppress error messages */
9871 r = getreply(x, /* Expect connection to close */
9872 lcs,rcs, /* Charsets */
9873 vbm, /* Verbosity */
9874 fc /* Function code */
9879 #ifdef CK_ENCRYPTION
9880 if (ftpcode == 533 && ftp_cpl == FPL_PRV) {
9882 "ENC command not supported at server; retrying under MIC...\n");
9886 #endif /* CK_ENCRYPTION */
9888 if (cancelfile && oldintr != SIG_IGN)
9890 #endif /* COMMENT */
9891 signal(SIGINT, oldintr);
9897 debug(F100,"lostpeer","",0);
9899 if (csocket != -1) {
9901 if (ssl_ftp_active_flag) {
9902 SSL_shutdown(ssl_ftp_con);
9903 SSL_free(ssl_ftp_con);
9905 ssl_ftp_active_flag = 0;
9910 socket_close(csocket);
9911 #else /* TCPIPLIB */
9913 shutdown(csocket, 1+1);
9914 #endif /* USE_SHUTDOWN */
9916 #endif /* TCPIPLIB */
9921 if (ssl_ftp_data_active_flag) {
9922 SSL_shutdown(ssl_ftp_data_con);
9923 SSL_free(ssl_ftp_data_con);
9924 ssl_ftp_data_active_flag = 0;
9925 ssl_ftp_data_con = NULL;
9930 #else /* TCPIPLIB */
9932 shutdown(data, 1+1);
9933 #endif /* USE_SHUTDOWN */
9935 #endif /* TCPIPLIB */
9943 ftp_cpl = ftp_dpl = FPL_CLR;
9946 #endif /* CKLOGDIAL */
9949 if (autolocus) /* Auotomatic locus switching... */
9950 setlocus(1,1); /* Switch locus to local. */
9953 DialerSend(OPT_KERMIT_HANGUP, 0);
9959 if (csocket != -1) {
9961 socket_close(csocket);
9962 #else /* TCPIPLIB */
9964 shutdown(csocket, 1+1);
9965 #endif /* USE_SHUTDOWN */
9967 #endif /* TCPIPLIB */
9974 ftp_cpl = ftp_dpl = FPL_CLR;
9978 #endif /* FTP_PROXY */
9988 extern int quitting;
9991 ftp_xfermode = xfermode;
9992 if (!ftp_vbm && !quiet)
9994 ftpcmd("QUIT",NULL,0,0,ftp_vbm);
9997 if (ssl_ftp_active_flag) {
9998 SSL_shutdown(ssl_ftp_con);
9999 SSL_free(ssl_ftp_con);
10001 ssl_ftp_active_flag = 0;
10002 ssl_ftp_con = NULL;
10004 #endif /* CK_SSL */
10006 socket_close(csocket);
10007 #else /* TCPIPLIB */
10008 #ifdef USE_SHUTDOWN
10009 shutdown(csocket, 1+1);
10010 #endif /* USE_SHUTDOWN */
10012 #endif /* TCPIPLIB */
10028 #endif /* FTP_PROXY */
10033 #endif /* CKLOGDIAL */
10035 /* Unprefixed file management commands are executed locally */
10036 if (autolocus && !ftp_cmdlin && !quitting) {
10041 DialerSend(OPT_KERMIT_HANGUP, 0);
10047 ftpopen(remote, service, use_tls) char * remote, * service; int use_tls; {
10051 printf("?Already connected to %s, use FTP CLOSE first.\n", ftp_host);
10057 #endif /* FTPHOST */
10059 ftp_srvtyp[0] = NUL;
10060 if (!service) service = "";
10061 if (!*service) service = use_tls ? "ftps" : "ftp";
10063 if (!isdigit(service[0])) {
10064 struct servent *destsp;
10065 destsp = getservbyname(service, "tcp");
10067 if (!ckstrcmp(service,"ftp",-1,0)) {
10069 } else if (!ckstrcmp(service,"ftps",-1,0)) {
10072 printf("?Bad port name - \"%s\"\n", service);
10077 ftp_port = destsp->s_port;
10078 ftp_port = ntohs((unsigned short)ftp_port); /* SMS 2007/02/15 */
10081 ftp_port = atoi(service);
10082 if (ftp_port <= 0) {
10083 printf("?Bad port name - \"%s\"\n", service);
10087 host = ftp_hookup(remote, ftp_port, use_tls);
10089 ckstrncpy(ftp_user_host,remote,MAX_DNS_NAMELEN);
10090 connected = 1; /* Set FTP defaults */
10091 ftp_cpl = ftp_dpl = FPL_CLR;
10092 curtype = FTT_ASC; /* Server uses ASCII mode */
10096 strcpy(bytename, "8");
10099 #ifdef FTP_SECURITY
10104 && ck_crypt_is_installed()
10108 printf("FTP Command channel is Private (encrypted)\n");
10110 if (setpbsz(DEFAULT_PBSZ) < 0) {
10111 /* a failure here is most likely caused by a mixup */
10112 /* in the session key used by client and server */
10113 printf("?Protection buffer size negotiation failed\n");
10116 if (ftpcmd("PROT P",NULL,0,0,ftp_vbm) == REPLY_COMPLETE) {
10118 printf("FTP Data channel is Private (encrypted)\n");
10121 printf("?Unable to enable encryption on data channel\n");
10129 #endif /* FTP_SECURITY */
10130 if (ftp_log) /* ^^^ */
10136 ftp_xfermode = xfermode;
10140 #endif /* CKLOGDIAL */
10142 DialerSend(OPT_KERMIT_CONNECT, 0);
10144 passivemode = ftp_psv;
10145 sendport = ftp_spc;
10151 if (ucbuf == NULL) {
10152 actualbuf = DEFAULT_PBSZ;
10153 while (actualbuf && (ucbuf = (CHAR *)malloc(actualbuf)) == NULL)
10157 ucbufsiz = actualbuf - FUDGE_FACTOR;
10158 debug(F101,"ftpopen ucbufsiz","",ucbufsiz);
10162 printf("?Can't FTP connect to %s:%s\n",remote,service);
10173 if (ssl_debug_flag) {
10174 fprintf(stderr,"SSL DEBUG ACTIVE\n");
10176 /* for the moment I want the output on screen */
10178 if (ssl_ftp_data_con != NULL) {
10179 SSL_free(ssl_ftp_data_con);
10180 ssl_ftp_data_con = NULL;
10182 if (ssl_ftp_con != NULL) {
10183 SSL_free(ssl_ftp_con);
10186 if (ssl_ftp_ctx != NULL) {
10187 SSL_CTX_free(ssl_ftp_ctx);
10188 ssl_ftp_ctx = NULL;
10191 /* The SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
10192 * was added to OpenSSL 0.9.6e and 0.9.7. It does not exist in previous
10195 #ifndef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
10196 #define SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS 0L
10198 if (auth_type && !strcmp(auth_type,"TLS")) {
10199 ssl_ftp_ctx=SSL_CTX_new(SSLv3_client_method());
10202 SSL_CTX_set_options(ssl_ftp_ctx,
10203 SSL_OP_SINGLE_DH_USE|SSL_OP_EPHEMERAL_RSA
10206 ssl_ftp_ctx = SSL_CTX_new(ftp_bug_use_ssl_v2 ? SSLv23_client_method() :
10207 SSLv3_client_method());
10210 SSL_CTX_set_options(ssl_ftp_ctx,
10211 (ftp_bug_use_ssl_v2 ? 0 : SSL_OP_NO_SSLv2)|
10212 SSL_OP_SINGLE_DH_USE|SSL_OP_EPHEMERAL_RSA
10215 SSL_CTX_set_default_passwd_cb(ssl_ftp_ctx,
10216 (pem_password_cb *)ssl_passwd_callback);
10217 SSL_CTX_set_info_callback(ssl_ftp_ctx,ssl_client_info_callback);
10218 SSL_CTX_set_session_cache_mode(ssl_ftp_ctx,SSL_SESS_CACHE_CLIENT);
10222 /* The defaults in the SSL crypto library are not appropriate for OS/2 */
10224 char path[CKMAXPATH];
10225 extern char exedir[];
10227 ckmakmsg(path,CKMAXPATH,exedir,"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(1),"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,
10243 (char *)GetAppData(0),"kermit 95/certs",NULL,NULL);
10244 if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,NULL,path) == 0) {
10245 debug(F110,"ftp ssl_auth unable to load path",path,0);
10246 if (ssl_debug_flag)
10247 printf("?Unable to load verify-dir: %s\r\n",path);
10250 ckmakmsg(path,CKMAXPATH,exedir,"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(1),
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);
10265 ckmakmsg(path,CKMAXPATH,(char *)GetAppData(0),
10266 "kermit 95/ca_certs.pem",NULL,NULL);
10267 if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,path,NULL) == 0) {
10268 debug(F110,"ftp ssl_auth unable to load path",path,0);
10269 if (ssl_debug_flag)
10270 printf("?Unable to load verify-file: %s\r\n",path);
10274 /* The defaults in the SSL crypto library are not appropriate for OS/2 */
10277 char path[CKMAXPATH];
10278 extern char exedir[];
10280 ckmakmsg(path,CKMAXPATH,exedir,"certs",NULL,NULL);
10281 if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,NULL,path) == 0) {
10282 debug(F110,"ftp ssl_auth unable to load path",path,0);
10283 if (ssl_debug_flag)
10284 printf("?Unable to load verify-dir: %s\r\n",path);
10286 ckmakmsg(path,CKMAXPATH,exedir,"ca_certs.pem",NULL,NULL);
10287 if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,path,NULL) == 0) {
10288 debug(F110,"ftp ssl_auth unable to load path",path,0);
10289 if (ssl_debug_flag)
10290 printf("?Unable to load verify-file: %s\r\n",path);
10295 SSL_CTX_set_default_verify_paths(ssl_ftp_ctx);
10298 if (ssl_verify_file &&
10299 SSL_CTX_load_verify_locations(ssl_ftp_ctx,ssl_verify_file,NULL) == 0) {
10301 "ftp ssl auth unable to load ssl_verify_file",
10305 if (ssl_debug_flag)
10306 printf("?Unable to load verify-file: %s\r\n",ssl_verify_file);
10308 if (ssl_verify_dir &&
10309 SSL_CTX_load_verify_locations(ssl_ftp_ctx,NULL,ssl_verify_dir) == 0) {
10311 "ftp ssl auth unable to load ssl_verify_dir",
10315 if (ssl_debug_flag)
10316 printf("?Unable to load verify-dir: %s\r\n",ssl_verify_dir);
10319 /* set up the new CRL Store */
10320 crl_store = (X509_STORE *)X509_STORE_new();
10323 char path[CKMAXPATH];
10324 extern char exedir[];
10326 ckmakmsg(path,CKMAXPATH,exedir,"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);
10333 ckmakmsg(path,CKMAXPATH,
10334 (char *)GetAppData(1),"kermit 95/crls",NULL,NULL);
10335 if (X509_STORE_load_locations(crl_store,NULL,path) == 0) {
10336 debug(F110,"ftp ssl auth unable to load dir",path,0);
10337 if (ssl_debug_flag)
10338 printf("?Unable to load crl-dir: %s\r\n",path);
10340 ckmakmsg(path,CKMAXPATH,
10341 (char *)GetAppData(0),"kermit 95/crls",NULL,NULL);
10342 if (X509_STORE_load_locations(crl_store,NULL,path) == 0) {
10343 debug(F110,"ftp ssl auth unable to load dir",path,0);
10344 if (ssl_debug_flag)
10345 printf("?Unable to load crl-dir: %s\r\n",path);
10349 ckmakmsg(path,CKMAXPATH,exedir,"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);
10356 ckmakmsg(path,CKMAXPATH,(char *)GetAppData(1),
10357 "kermit 95/ca_crls.pem",NULL,NULL);
10358 if (X509_STORE_load_locations(crl_store,path,NULL) == 0) {
10359 debug(F110,"ftp ssl auth unable to load file",path,0);
10360 if (ssl_debug_flag)
10361 printf("?Unable to load crl-file: %s\r\n",path);
10363 ckmakmsg(path,CKMAXPATH,(char *)GetAppData(0),
10364 "kermit 95/ca_crls.pem",NULL,NULL);
10365 if (X509_STORE_load_locations(crl_store,path,NULL) == 0) {
10366 debug(F110,"ftp ssl auth unable to load file",path,0);
10367 if (ssl_debug_flag)
10368 printf("?Unable to load crl-file: %s\r\n",path);
10373 if (ssl_crl_file || ssl_crl_dir) {
10374 if (ssl_crl_file &&
10375 X509_STORE_load_locations(crl_store,ssl_crl_file,NULL) == 0) {
10377 "ftp ssl auth unable to load ssl_crl_file",
10381 if (ssl_debug_flag)
10382 printf("?Unable to load crl-file: %s\r\n",ssl_crl_file);
10385 X509_STORE_load_locations(crl_store,NULL,ssl_crl_dir) == 0) {
10387 "ftp ssl auth unable to load ssl_crl_dir",
10391 if (ssl_debug_flag)
10392 printf("?Unable to load crl-dir: %s\r\n",ssl_crl_dir);
10395 X509_STORE_set_default_paths(crl_store);
10398 SSL_CTX_set_verify(ssl_ftp_ctx,ssl_verify_flag,
10399 ssl_client_verify_callback);
10400 ssl_verify_depth = -1;
10401 ssl_ftp_con=(SSL *)SSL_new(ssl_ftp_ctx);
10402 tls_load_certs(ssl_ftp_ctx,ssl_ftp_con,0);
10403 SSL_set_fd(ssl_ftp_con,csocket);
10404 SSL_set_verify(ssl_ftp_con,ssl_verify_flag,NULL);
10405 if (ssl_cipher_list) {
10406 SSL_set_cipher_list(ssl_ftp_con,ssl_cipher_list);
10409 if (p = getenv("SSL_CIPHER")) {
10410 SSL_set_cipher_list(ssl_ftp_con,p);
10412 SSL_set_cipher_list(ssl_ftp_con,DEFAULT_CIPHER_LIST);
10415 if (ssl_debug_flag) {
10416 fprintf(stderr,"=>START SSL/TLS connect on COMMAND\n");
10419 if (SSL_connect(ssl_ftp_con) <= 0) {
10420 static char errbuf[1024];
10421 ckmakmsg(errbuf,1024,"ftp: SSL/TLS connect COMMAND error: ",
10422 ERR_error_string(ERR_get_error(),NULL),NULL,NULL);
10423 fprintf(stderr,"%s\n", errbuf);
10425 ssl_ftp_active_flag=0;
10426 SSL_free(ssl_ftp_con);
10427 ssl_ftp_con = NULL;
10429 ssl_ftp_active_flag = 1;
10431 if (!ssl_certsok_flag && !tls_is_krb5(1)) {
10432 char *subject = ssl_get_subject_name(ssl_ftp_con);
10435 if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
10436 debug(F110,"ssl_auth","[SSL - FAILED]",0);
10437 return(ssl_ftp_active_flag = 0);
10439 if (uq_ok("Warning: Server didn't provide a certificate\n",
10440 "Continue? (Y/N)",3,NULL,0) <= 0) {
10441 debug(F110, "ssl_auth","[SSL - FAILED]",0);
10442 return(ssl_ftp_active_flag = 0);
10445 } else if (ssl_check_server_name(ssl_ftp_con, ftp_user_host)) {
10446 debug(F110,"ssl_auth","[SSL - FAILED]",0);
10447 return(ssl_ftp_active_flag = 0);
10450 debug(F110,"ssl_auth","[SSL - OK]",0);
10451 ssl_display_connect_details(ssl_ftp_con,0,ssl_verbose_flag);
10453 if (ssl_debug_flag) {
10454 fprintf(stderr,"=>DONE SSL/TLS connect on COMMAND\n");
10457 return(ssl_ftp_active_flag);
10459 #endif /* CK_SSL */
10462 cmdcancel(sig) int sig; {
10464 /* In Unix we "chain" to trap(), which prints this */
10467 debug(F100,"ftp cmdcancel caught SIGINT ","",0);
10469 secure_getc(0,1); /* Initialize net input buffers */
10475 if (ptflag) /* proxy... */
10476 longjmp(ptcancel,1);
10477 #endif /* FTP_PROXY */
10478 debug(F100,"ftp cmdcancel chain to trap()...","",0);
10481 debug(F100,"ftp cmdcancel return from trap()...","",0);
10483 debug(F100,"ftp cmdcancel PostCtrlCSem()...","",0);
10490 scommand(char * s) /* Was secure_command() */
10492 scommand(s) char * s;
10493 #endif /* CK_ANSIC */
10495 int length = 0, len2;
10496 char in[FTP_BUFSIZ], out[FTP_BUFSIZ];
10498 if (ssl_ftp_active_flag) {
10500 length = strlen(s) + 2;
10501 length = ckmakmsg(out,FTP_BUFSIZ,s,"\r\n",NULL,NULL);
10502 rc = SSL_write(ssl_ftp_con,out,length);
10503 error = SSL_get_error(ssl_ftp_con,rc);
10505 case SSL_ERROR_NONE:
10507 case SSL_ERROR_WANT_WRITE:
10508 case SSL_ERROR_WANT_READ:
10509 case SSL_ERROR_SYSCALL:
10512 int gle = GetLastError();
10515 case SSL_ERROR_WANT_X509_LOOKUP:
10516 case SSL_ERROR_SSL:
10517 case SSL_ERROR_ZERO_RETURN:
10523 #endif /* CK_SSL */
10525 if (auth_type && ftp_cpl != FPL_CLR) {
10527 if (ck_srp_is_installed() && (strcmp(auth_type,"SRP") == 0))
10528 if ((length = srp_encode(ftp_cpl == FPL_PRV,
10532 fprintf(stderr, "SRP failed to encode message\n");
10535 #endif /* FTP_SRP */
10537 if (ck_krb4_is_installed() &&
10538 (strcmp(auth_type, "KERBEROS_V4") == 0)) {
10539 if (ftp_cpl == FPL_PRV) {
10541 krb_mk_priv((CHAR *)s, (CHAR *)out,
10542 strlen(s), ftp_sched,
10547 #endif /* KRB524 */
10548 &myctladdr, &hisctladdr);
10551 krb_mk_safe((CHAR *)s,
10558 #endif /* KRB524 */
10559 &myctladdr, &hisctladdr);
10561 if (length == -1) {
10562 fprintf(stderr, "krb_mk_%s failed for KERBEROS_V4\n",
10563 ftp_cpl == FPL_PRV ? "priv" : "safe");
10567 #endif /* FTP_KRB4 */
10569 /* Scommand (based on level) */
10570 if (ck_gssapi_is_installed() && (strcmp(auth_type, "GSSAPI") == 0)) {
10571 gss_buffer_desc in_buf, out_buf;
10572 OM_uint32 maj_stat, min_stat;
10575 in_buf.length = strlen(s) + 1;
10576 maj_stat = gss_seal(&min_stat, gcontext,
10577 (ftp_cpl==FPL_PRV), /* private */
10579 &in_buf, &conf_state,
10581 if (maj_stat != GSS_S_COMPLETE) { /* Generally need to deal */
10582 user_gss_error(maj_stat, min_stat,
10583 (ftp_cpl==FPL_PRV)?
10584 "gss_seal ENC didn't complete":
10585 "gss_seal MIC didn't complete");
10586 } else if ((ftp_cpl == FPL_PRV) && !conf_state) {
10587 fprintf(stderr, "GSSAPI didn't encrypt message");
10590 fprintf(stderr, "sealed (%s) %d bytes\n",
10591 ftp_cpl==FPL_PRV?"ENC":"MIC",
10593 memcpy(out, out_buf.value,
10594 length=out_buf.length);
10595 gss_release_buffer(&min_stat, &out_buf);
10598 #endif /* FTP_GSSAPI */
10599 /* Other auth types go here ... */
10602 if ((kerror = radix_encode((CHAR *)out, (CHAR *)in,
10603 length, &len2, RADIX_ENCODE))
10605 fprintf(stderr,"Couldn't base 64 encode command (%s)\n",
10606 radix_error(kerror));
10610 fprintf(stderr, "scommand(%s)\nencoding %d bytes\n", s, length);
10611 len2 = ckmakmsg(out,
10613 ftp_cpl == FPL_PRV ? "ENC " : "MIC ",
10618 send(csocket,(SENDARG2TYPE)out,len2,0);
10620 char out[FTP_BUFSIZ];
10621 int len = ckmakmsg(out,FTP_BUFSIZ,s,"\r\n",NULL,NULL);
10622 send(csocket,(SENDARG2TYPE)out,len,0);
10629 static char inbuf[4096];
10630 static int bp = 0, ep = 0;
10636 if (ssl_ftp_active_flag) {
10638 rc = SSL_read(ssl_ftp_con,inbuf,4096);
10639 error = SSL_get_error(ssl_ftp_con,rc);
10641 case SSL_ERROR_NONE:
10643 case SSL_ERROR_WANT_WRITE:
10644 case SSL_ERROR_WANT_READ:
10646 case SSL_ERROR_SYSCALL:
10647 if (rc == 0) { /* EOF */
10651 int gle = GetLastError();
10655 case SSL_ERROR_WANT_X509_LOOKUP:
10656 case SSL_ERROR_SSL:
10657 case SSL_ERROR_ZERO_RETURN:
10662 #endif /* CK_SSL */
10663 rc = recv(csocket,(char *)inbuf,4096,0);
10668 return(inbuf[bp++]);
10671 /* x l a t e c -- Translate a character */
10674 fc = Function code: 0 = translate, 1 = initialize.
10675 c = Character (as int).
10676 incs = Index of charset to translate from.
10677 outcs = Index of charset to translate to.
10684 xlatec(fc,c,incs,outcs) int fc, c, incs, outcs; {
10688 static char buf[128];
10692 if (fc == 1) { /* Initialize */
10693 cx = 0; /* Catch-up buffer write index */
10694 xgnbp = buf; /* Catch-up buffer read pointer */
10695 buf[0] = NUL; /* Buffer is empty */
10698 if (cx >= 127) { /* Catch-up buffer full */
10699 debug(F100,"xlatec overflow","",0); /* (shouldn't happen) */
10700 printf("?Translation buffer overflow\n");
10703 /* Add char to buffer. */
10704 /* The buffer won't grow unless incs is a multibyte set, e.g. UTF-8. */
10706 debug(F000,"xlatec buf",ckitoa(cx),c);
10710 while ((c0 = xgnbyte(FC_UCS2,incs,strgetc)) > -1) {
10711 if (xpnbyte(c0,TC_UCS2,outcs,NULL) < 0) /* (NULL was xprintc) */
10714 /* If we're caught up, reinitialize the buffer */
10715 return((cx == (xgnbp - buf)) ? xlatec(1,0,0,0) : 0);
10716 #endif /* NOCSETS */
10720 /* p a r s e f e a t */
10722 /* Note: for convenience we align keyword values with table indices */
10723 /* If you need to insert a new keyword, adjust the SFT_xxx definitions */
10725 static struct keytab feattab[] = {
10726 { "$$$$", 0, 0 }, /* Dummy for sfttab[0] */
10727 { "AUTH", SFT_AUTH, 0 },
10728 { "LANG", SFT_LANG, 0 },
10729 { "MDTM", SFT_MDTM, 0 },
10730 { "MLST", SFT_MLST, 0 },
10731 { "PBSZ", SFT_PBSZ, 0 },
10732 { "PROT", SFT_PROT, 0 },
10733 { "REST", SFT_REST, 0 },
10734 { "SIZE", SFT_SIZE, 0 },
10735 { "TVFS", SFT_TVFS, 0 },
10736 { "UTF8", SFT_UTF8, 0 }
10738 static int nfeattab = (sizeof(feattab) / sizeof(struct keytab));
10740 #define FACT_CSET 1
10741 #define FACT_CREA 2
10742 #define FACT_LANG 3
10743 #define FACT_MTYP 4
10744 #define FACT_MDTM 5
10745 #define FACT_PERM 6
10746 #define FACT_SIZE 7
10747 #define FACT_TYPE 8
10748 #define FACT_UNIQ 9
10750 static struct keytab facttab[] = {
10751 { "CHARSET", FACT_CSET, 0 },
10752 { "CREATE", FACT_CREA, 0 },
10753 { "LANG", FACT_LANG, 0 },
10754 { "MEDIA-TYPE", FACT_MTYP, 0 },
10755 { "MODIFY", FACT_MDTM, 0 },
10756 { "PERM", FACT_PERM, 0 },
10757 { "SIZE", FACT_SIZE, 0 },
10758 { "TYPE", FACT_TYPE, 0 },
10759 { "UNIQUE", FACT_UNIQ, 0 }
10761 static int nfacttab = (sizeof(facttab) / sizeof(struct keytab));
10763 static struct keytab ftyptab[] = {
10764 { "CDIR", FTYP_CDIR, 0 },
10765 { "DIR", FTYP_DIR, 0 },
10766 { "FILE", FTYP_FILE, 0 },
10767 { "PDIR", FTYP_PDIR, 0 }
10769 static int nftyptab = (sizeof(ftyptab) / sizeof(struct keytab));
10772 parsefeat(s) char * s; { /* Parse a FEATURE response */
10779 for (i = 0; i < 4; i++) {
10784 if (s[i] && s[i] != SP && s[i] != CR && s[i] != LF)
10787 /* xlookup requires a full (but case independent) match */
10788 i = xlookup(feattab,kwbuf,nfeattab,&x);
10789 debug(F111,"ftp parsefeat",s,i);
10790 if (i < 0 || i > 15)
10794 case SFT_MDTM: /* Controlled by ENABLE/DISABLE */
10795 sfttab[i] = mdtmok;
10796 if (mdtmok) sfttab[0]++;
10798 case SFT_MLST: /* ditto */
10799 sfttab[i] = mlstok;
10800 if (mlstok) sfttab[0]++;
10802 case SFT_SIZE: /* ditto */
10803 sfttab[i] = sizeok;
10804 if (sizeok) sfttab[0]++;
10806 case SFT_AUTH: /* ditto */
10807 sfttab[i] = ftp_aut;
10808 if (ftp_aut) sfttab[0]++;
10810 default: /* Others */
10817 parsefacts(s) char * s; { /* Parse MLS[DT] File Facts */
10820 if (!s) return(NULL);
10821 if (!*s) return(NULL);
10823 /* Maybe we should make a copy of s so we can poke it... */
10825 while ((p = ckstrchr(s,'='))) {
10826 *p = NUL; /* s points to fact */
10827 i = xlookup(facttab,s,nfacttab,&x);
10828 debug(F111,"ftp parsefact fact",s,i);
10830 s = p+1; /* Now s points to arg */
10831 p = ckstrchr(s,';');
10833 p = ckstrchr(s,SP);
10835 debug(F110,"ftp parsefact end-of-val search fail",s,0);
10839 debug(F110,"ftp parsefact valu",s,0);
10841 case FACT_CSET: /* Ignore these for now */
10848 case FACT_MDTM: /* Modtime */
10849 makestr(&havemdtm,s);
10850 debug(F110,"ftp parsefact mdtm",havemdtm,0);
10852 case FACT_SIZE: /* Size */
10853 havesize = ckatofs(s);
10854 debug(F101,"ftp parsefact size","",havesize);
10856 case FACT_TYPE: /* Type */
10857 j = xlookup(ftyptab,s,nftyptab,NULL);
10858 debug(F111,"ftp parsefact type",s,j);
10859 havetype = (j < 1) ? 0 : j;
10863 s = p+1; /* s points next fact or name */
10865 while (*s == SP) /* Skip past spaces. */
10867 if (!*s) /* Make sure we still have a name */
10869 debug(F110,"ftp parsefact name",s,0);
10873 /* g e t r e p l y -- (to an FTP command sent to server) */
10875 /* vbm = 1 (verbose); 0 (quiet except for error messages); 9 (super quiet) */
10878 getreply(expecteof,lcs,rcs,vbm,fc) int expecteof, lcs, rcs, vbm, fc; {
10879 /* lcs, rcs, vbm parameters as in ftpcmd() */
10880 register int i, c, n;
10886 int originalcode = 0, continuation = 0;
10890 char ibuf[FTP_BUFSIZ], obuf[FTP_BUFSIZ]; /* (these are pretty big...) */
10894 auth = (fc == GRF_AUTH);
10897 debug(F101,"ftp getreply lcs","",lcs);
10898 debug(F101,"ftp getreply rcs","",rcs);
10899 if (lcs > -1 && rcs > -1 && lcs != rcs) {
10901 initxlate(rcs,lcs);
10902 xlatec(1,0,rcs,lcs);
10904 #endif /* NOCSETS */
10905 debug(F101,"ftp getreply fc","",fc);
10913 if (ftp_deb) /* DEBUG */
10915 else if (quiet || dpyactive) /* QUIET or File Transfer Active */
10917 else if (vbm < 0) /* VERBOSE */
10922 reply_ptr = reply_buf;
10924 oldintr = signal(SIGINT, cmdcancel);
10925 for (count = 0;; count++) {
10927 dig = n = ftpcode = i = 0;
10928 cp = ftp_reply_str;
10929 while ((c = ibuf[0] ? ibuf[i++] : mygetc()) != '\n') {
10930 if (c == IAC) { /* Handle telnet commands */
10931 switch (c = mygetc()) {
10940 if (ssl_ftp_active_flag) {
10942 rc = SSL_write(ssl_ftp_con,obuf,3);
10943 error = SSL_get_error(ssl_ftp_con,rc);
10945 case SSL_ERROR_NONE:
10947 case SSL_ERROR_WANT_WRITE:
10948 case SSL_ERROR_WANT_READ:
10950 case SSL_ERROR_SYSCALL:
10951 if (rc == 0) { /* EOF */
10955 int gle = GetLastError();
10959 case SSL_ERROR_WANT_X509_LOOKUP:
10960 case SSL_ERROR_SSL:
10961 case SSL_ERROR_ZERO_RETURN:
10966 #endif /* CK_SSL */
10967 send(csocket,(SENDARG2TYPE)obuf,3,0);
10977 if (ssl_ftp_active_flag) {
10979 rc = SSL_write(ssl_ftp_con,obuf,3);
10980 error = SSL_get_error(ssl_ftp_con,rc);
10982 case SSL_ERROR_NONE:
10984 case SSL_ERROR_WANT_WRITE:
10985 case SSL_ERROR_WANT_READ:
10986 signal(SIGINT,oldintr);
10988 case SSL_ERROR_SYSCALL:
10989 if (rc == 0) { /* EOF */
10993 int gle = GetLastError();
10997 case SSL_ERROR_WANT_X509_LOOKUP:
10998 case SSL_ERROR_SSL:
10999 case SSL_ERROR_ZERO_RETURN:
11004 #endif /* CK_SSL */
11005 send(csocket,(SENDARG2TYPE)obuf,3,0);
11015 signal(SIGINT,oldintr);
11017 debug(F101,"ftp getreply EOF","",ftpcode);
11025 "Service not available, connection closed by server\n");
11028 signal(SIGINT,oldintr);
11030 debug(F101,"ftp getreply EOF","",ftpcode);
11033 if (n == 0) { /* First digit */
11034 n = c; /* Save it */
11038 !ssl_ftp_active_flag &&
11039 #endif /* CK_SSL */
11040 !ibuf[0] && (n == '6' || continuation)) {
11041 if (c != '\r' && dig > 4)
11046 !ssl_ftp_active_flag &&
11047 #endif /* CK_SSL */
11048 !ibuf[0] && dig == 1 && vbm)
11049 printf("Unauthenticated reply received from server:\n");
11054 if ((!dpyactive || ftp_deb) && /* Don't mess up xfer display */
11057 (ftp_deb || ((vbm || (!auth && n == '5')) &&
11058 (dig > 4 || ( dig <= 4 && !isdigit(c) && ftpcode == 0
11062 if (ftp_prx && (dig == 1 || (dig == 5 && vbm == 0)))
11063 printf("%s:",ftp_host);
11064 #endif /* FTP_PROXY */
11071 xlatec(0,c,rcs,lcs);
11075 #endif /* NOCSETS */
11082 !ssl_ftp_active_flag &&
11083 #endif /* CK_SSL */
11084 !ibuf[0] && n != '6')
11086 if (dig < 4 && isdigit(c))
11087 ftpcode = ftpcode * 10 + (c - '0');
11088 if (!pflag && ftpcode == 227)
11090 if (dig > 4 && pflag == 1 && isdigit(c))
11093 if (c != '\r' && c != ')')
11100 if (dig == 4 && c == '-' && n != '6') {
11105 if (cp < &ftp_reply_str[FTP_BUFSIZ - 1]) {
11113 Sometimes we need to print the server reply. printlines is nonzero for any
11114 command where the results are sent back on the control connection rather
11115 than the data connection, e.g. STAT. In the TOPS-20 case, each file line
11116 has ftpcode 213. But if you do this with a UNIX server, it sends "213-Start
11117 STAT", <line with ftpcode == 0>, "213-End" or somesuch. So when printlines
11118 is nonzero, we want the 213 lines from TOPS-20 and we DON'T want the 213
11119 lines from UNIX. Further experimentation needed with other servers. Of
11120 course RFC959 is mute as to the format of the server reply.
11122 'printlines' is also true for PWD and BYE.
11124 (printlines && ((ftpcode == 0) || (servertype == SYS_TOPS20)))
11126 /* No, we can't be that clever -- it breaks other things like RPWD... */
11128 (ftpcode != 631 && ftpcode != 632 && ftpcode != 633))
11129 #endif /* COMMENT */
11132 char *r = ftp_reply_str;
11133 *q-- = NUL; /* NUL-terminate */
11134 while (*q < '!' && q > r) /* Strip CR, etc */
11136 if (!ftp_deb && printlines) { /* If printing */
11137 if (ftpcode != 0) /* strip ftpcode if any */
11140 printf("%s\n",r); /* and print */
11144 } else { /* Translating */
11145 xgnbp = r; /* Set up strgetc() */
11146 while ((c0 = xgnbyte(FC_UCS2,rcs,strgetc)) > -1) {
11147 if (xpnbyte(c0,TC_UCS2,lcs,NULL) < 0) { /* (xprintc) */
11148 signal(SIGINT,oldintr);
11154 #endif /* NOCSETS */
11157 debug(F110,"FTP RCVD ",ftp_reply_str,0);
11159 if (fc == GRF_FEAT) { /* Parsing FEAT command response? */
11160 if (count == 0 && n == '2') {
11161 int i; /* (Re)-init server FEATure table */
11162 debug(F100,"ftp getreply clearing feature table","",0);
11163 for (i = 0; i < 16; i++)
11166 parsefeat((char *)ftp_reply_str);
11171 !ssl_ftp_active_flag &&
11172 #endif /* CK_SSL */
11173 !ibuf[0] && n != '6') {
11174 signal(SIGINT,oldintr);
11175 return(getreply(expecteof,lcs,rcs,vbm,auth));
11177 ibuf[0] = obuf[i] = '\0';
11178 if (ftpcode && n == '6')
11179 if (ftpcode != 631 && ftpcode != 632 && ftpcode != 633) {
11180 printf("Unknown reply: %d %s\n", ftpcode, obuf);
11182 } else safe = (ftpcode == 631);
11183 if (obuf[0] /* if there is a string to decode */
11185 && !ssl_ftp_active_flag /* and not SSL/TLS */
11186 #endif /* CK_SSL */
11189 printf("Cannot decode reply:\n%d %s\n", ftpcode, obuf);
11192 #ifndef CK_ENCRYPTION
11193 else if (ftpcode == 632) {
11194 printf("Cannot decrypt %d reply: %s\n", ftpcode, obuf);
11197 #endif /* CK_ENCRYPTION */
11198 #ifdef NOCONFIDENTIAL
11199 else if (ftpcode == 633) {
11200 printf("Cannot decrypt %d reply: %s\n", ftpcode, obuf);
11203 #endif /* NOCONFIDENTIAL */
11205 int len = FTP_BUFSIZ;
11206 if ((kerror = radix_encode((CHAR *)obuf,
11212 printf("Can't decode base 64 reply %d (%s)\n\"%s\"\n",
11213 ftpcode, radix_error(kerror), obuf);
11217 else if (strcmp(auth_type, "SRP") == 0) {
11219 outlen = srp_decode(!safe, (CHAR *)ibuf,
11220 (CHAR *) ibuf, len);
11222 printf("Warning: %d reply %s!\n",
11223 ftpcode, safe ? "modified" : "garbled");
11226 ckstrncpy(&ibuf[outlen], "\r\n",FTP_BUFSIZ-outlen);
11228 printf("%c:", safe ? 'S' : 'P');
11232 #endif /* FTP_SRP */
11234 else if (strcmp(auth_type, "KERBEROS_V4") == 0) {
11236 kerror = krb_rd_safe((CHAR *)ibuf, len,
11241 #endif /* KRB524 */
11247 kerror = krb_rd_priv((CHAR *)ibuf, len,
11253 #endif /* KRB524 */
11259 if (kerror != KSUCCESS) {
11260 printf("%d reply %s! (krb_rd_%s: %s)\n", ftpcode,
11261 safe ? "modified" : "garbled",
11262 safe ? "safe" : "priv",
11263 krb_get_err_text(kerror));
11265 } else if (ftp_msg_data.app_length >= FTP_BUFSIZ - 3) {
11268 printf("reply data too large for buffer\n");
11271 printf("%c:", safe ? 'S' : 'P');
11272 memcpy(ibuf,ftp_msg_data.app_data,
11273 ftp_msg_data.app_length);
11274 ckstrncpy(&ibuf[ftp_msg_data.app_length], "\r\n",
11275 FTP_BUFSIZ - ftp_msg_data.app_length);
11279 #endif /* FTP_KRB4 */
11281 else if (strcmp(auth_type, "GSSAPI") == 0) {
11282 gss_buffer_desc xmit_buf, msg_buf;
11283 OM_uint32 maj_stat, min_stat;
11285 xmit_buf.value = ibuf;
11286 xmit_buf.length = len;
11287 /* decrypt/verify the message */
11289 maj_stat = gss_unseal(&min_stat, gcontext,
11290 &xmit_buf, &msg_buf,
11291 &conf_state, NULL);
11292 if (maj_stat != GSS_S_COMPLETE) {
11293 user_gss_error(maj_stat, min_stat,
11294 "failed unsealing reply");
11297 memcpy(ibuf, msg_buf.value, msg_buf.length);
11298 ckstrncpy(&ibuf[msg_buf.length], "\r\n",
11299 FTP_BUFSIZ-msg_buf.length);
11300 gss_release_buffer(&min_stat,&msg_buf);
11302 printf("%c:", safe ? 'S' : 'P');
11306 #endif /* FTP_GSSAPI */
11307 /* Other auth types go here... */
11309 } else if ((!dpyactive || ftp_deb) && ftp_cmdlin < 2 &&
11310 !xquiet && (vbm || (!auth && (n == '4' || n == '5')))) {
11315 xlatec(0,c,rcs,lcs);
11319 #endif /* NOCSETS */
11322 if (continuation && ftpcode != originalcode) {
11323 if (originalcode == 0)
11324 originalcode = ftpcode;
11330 signal(SIGINT,oldintr);
11331 if (ftpcode == 421 || originalcode == 421) {
11333 if (!xquiet && !ftp_deb)
11334 printf("%s\n",reply_buf);
11336 if ((cancelfile != 0) &&
11338 /* Ultrix 3.0 cc objects violently to this clause */
11339 (oldintr != cmdcancel) &&
11340 #endif /* ULTRIX3 */
11341 (oldintr != SIG_IGN)) {
11343 (*oldintr)(SIGINT);
11347 if ((reply_ptr = ckstrstr(reply_buf, reply_parse))) {
11348 reply_parse = reply_ptr + strlen(reply_parse);
11349 if ((reply_ptr = ckstrpbrk(reply_parse, " \r")))
11352 reply_parse = reply_ptr;
11354 while (*cp < '!' && cp > ftp_reply_str) /* Remove trailing junk */
11356 debug(F111,"ftp getreply",ftp_reply_str,n - '0');
11364 empty(fd_set * mask, int sec)
11366 empty(mask, sec) fd_set * mask; int sec;
11367 #endif /* CK_ANSIC */
11370 t.tv_sec = (long) sec;
11372 debug(F100,"ftp empty calling select...","",0);
11374 x = select(32, (int *)mask, NULL, NULL, &t);
11376 x = select(32, mask, (fd_set *) 0, (fd_set *) 0, &t);
11377 #endif /* INTSELECT */
11378 debug(F101,"ftp empty select","",x);
11381 #else /* BSDSELECT */
11384 empty(mask, cnt, sec) int * mask, sec;
11387 return(select(mask,cnt,0,0,sec*1000));
11389 #endif /* IBMSELECT */
11390 #endif /* BSDSELECT */
11393 cancelsend(sig) int sig; {
11397 printf(" Canceled...\n");
11398 secure_getc(0,1); /* Initialize net input buffers */
11399 debug(F100,"ftp cancelsend caught SIGINT ","",0);
11402 longjmp(sendcancel, 1);
11410 secure_error(char *fmt, ...)
11413 secure_error(fmt, p1, p2, p3, p4, p5)
11414 char *fmt; int p1, p2, p3, p4, p5;
11415 #endif /* CK_ANSIC */
11421 vfprintf(stderr, fmt, ap);
11424 fprintf(stderr, fmt, p1, p2, p3, p4, p5);
11426 fprintf(stderr, "\n");
11430 * Internal form of settype; changes current type in use with server
11431 * without changing our notion of the type for data transfers.
11432 * Used to change to and from ascii for listings.
11435 changetype(newtype, show) int newtype, show; {
11439 if ((newtype == curtype) && typesent++)
11455 rc = ftpcmd("TYPE",s,-1,-1,show);
11456 if (rc == REPLY_COMPLETE)
11460 /* PUT a file. Returns -1 on error, 0 on success, 1 if file skipped */
11464 doftpsend(void * threadinfo)
11466 doftpsend(threadinfo) VOID * threadinfo;
11470 if (threadinfo) { /* Thread local storage... */
11471 TlsSetValue(TlsIndex,threadinfo);
11472 debug(F100, "doftpsend called with threadinfo block","", 0);
11473 } else debug(F100, "doftpsend - threadinfo is NULL", "", 0);
11482 #endif /* CK_LOGIN */
11487 /* debug(F101,"doftpsend","tcp_http_proxy",tcp_http_proxy); */
11489 /* If the connection failed and we are using an HTTP Proxy
11490 * and the reason for the failure was an authentication
11491 * error, then we need to give the user to ability to
11492 * enter a username and password, just like a browser.
11494 * I tried to do all of this within the netopen() call
11495 * but it is much too much work.
11497 while (y != 0 && tcp_http_proxy != NULL ) {
11499 if (tcp_http_proxy_errno == 401 ||
11500 tcp_http_proxy_errno == 407 ) {
11501 char uid[UIDBUFLEN];
11503 struct txtbox tb[2];
11507 tb[0].t_len = UIDBUFLEN;
11508 tb[0].t_lbl = "Proxy Userid: ";
11509 tb[0].t_dflt = NULL;
11513 tb[1].t_lbl = "Proxy Passphrase: ";
11514 tb[1].t_dflt = NULL;
11517 ok = uq_mtxt("Proxy Server Authentication Required\n",
11519 if (ok && uid[0]) {
11520 char * proxy_user, * proxy_pwd;
11522 proxy_user = tcp_http_proxy_user;
11523 proxy_pwd = tcp_http_proxy_pwd;
11525 tcp_http_proxy_user = uid;
11526 tcp_http_proxy_pwd = pwd;
11530 debug(F101,"doftpsend","initconn",y);
11531 memset(pwd,0,PWDSIZ);
11532 tcp_http_proxy_user = proxy_user;
11533 tcp_http_proxy_pwd = proxy_pwd;
11541 #endif /* NOHTTP */
11542 signal(SIGINT, ftpsnd.oldintr);
11544 if (ftpsnd.oldintp)
11545 signal(SIGPIPE, ftpsnd.oldintp);
11546 #endif /* SIGPIPE */
11551 ckThreadEnd(threadinfo);
11556 #endif /* NOHTTP */
11560 ckThreadEnd(threadinfo);
11566 failftpsend(void * threadinfo)
11568 failftpsend(threadinfo) VOID * threadinfo;
11569 #endif /* CK_ANSIC */
11572 if (threadinfo) { /* Thread local storage... */
11573 TlsSetValue(TlsIndex,threadinfo);
11574 debug(F100, "docmdfile called with threadinfo block","", 0);
11575 } else debug(F100, "docmdfile - threadinfo is NULL", "", 0);
11584 #endif /* CK_LOGIN */
11587 ftpsnd.reply = getreply(0,ftpsnd.incs,ftpsnd.outcs,ftp_vbm,0);
11588 debug(F111,"ftp sendrequest getreply","null command",ftpsnd.reply);
11592 if (ssl_ftp_data_active_flag) {
11593 SSL_shutdown(ssl_ftp_data_con);
11594 SSL_free(ssl_ftp_data_con);
11595 ssl_ftp_data_active_flag = 0;
11596 ssl_ftp_data_con = NULL;
11598 #endif /* CK_SSL */
11600 socket_close(data);
11601 #else /* TCPIPLIB */
11602 #ifdef USE_SHUTDOWN
11603 shutdown(data, 1+1);
11604 #endif /* USE_SHUTDOWN */
11606 #endif /* TCPIPLIB */
11610 if (ftpsnd.oldintr)
11611 signal(SIGINT,ftpsnd.oldintr);
11613 if (ftpsnd.oldintp)
11614 signal(SIGPIPE,ftpsnd.oldintp);
11615 #endif /* SIGPIPE */
11618 /* TEST ME IN K95 */
11621 debug(F100,"ftp failftpsend chain to trap()...","",0);
11622 if (ftpsnd.oldintr != SIG_IGN)
11623 (*ftpsnd.oldintr)(SIGINT);
11624 /* NOTREACHED (I hope!) */
11625 debug(F100,"ftp failftpsend return from trap()...","",0);
11632 failftpsend2(void * threadinfo)
11634 failftpsend2(threadinfo) VOID * threadinfo;
11635 #endif /* CK_ANSIC */
11638 if (threadinfo) { /* Thread local storage... */
11639 TlsSetValue(TlsIndex,threadinfo);
11640 debug(F100, "docmdfile called with threadinfo block","", 0);
11641 } else debug(F100, "docmdfile - threadinfo is NULL", "", 0);
11650 #endif /* CK_LOGIN */
11652 debug(F101,"ftp sendrequest canceled","",ftpsnd.bytes);
11655 fpfsecs = gftimer();
11656 #endif /* GFTIMER */
11661 #endif /* PIPESEND */
11662 signal(SIGINT, ftpsnd.oldintr);
11664 if (ftpsnd.oldintp)
11665 signal(SIGPIPE, ftpsnd.oldintp);
11666 #endif /* SIGPIPE */
11671 ckThreadEnd(threadinfo);
11677 if (ssl_ftp_data_active_flag) {
11678 SSL_shutdown(ssl_ftp_data_con);
11679 SSL_free(ssl_ftp_data_con);
11680 ssl_ftp_data_active_flag = 0;
11681 ssl_ftp_data_con = NULL;
11683 #endif /* CK_SSL */
11685 socket_close(data);
11686 #else /* TCPIPLIB */
11687 #ifdef USE_SHUTDOWN
11688 shutdown(data, 1+1);
11689 #endif /* USE_SHUTDOWN */
11691 #endif /* TCPIPLIB */
11697 socket_close(dout);
11698 #else /* TCPIPLIB */
11699 #ifdef USE_SHUTDOWN
11700 shutdown(dout, 1+1);
11701 #endif /* USE_SHUTDOWN */
11703 #endif /* TCPIPLIB */
11705 ftpsnd.reply = getreply(0,ftpsnd.incs,ftpsnd.outcs,ftp_vbm,0);
11710 /* TEST ME IN K95 */
11713 debug(F100,"ftp failftpsend2 chain to trap()...","",0);
11714 if (ftpsnd.oldintr != SIG_IGN)
11715 (*ftpsnd.oldintr)(SIGINT);
11716 /* NOTREACHED (I hope!) */
11717 debug(F100,"ftp failftpsend2 return from trap()...","",0);
11724 doftpsend2(void * threadinfo)
11726 doftpsend2(threadinfo) VOID * threadinfo;
11729 register int c, d = 0;
11730 int n, t, x, notafile, unique = 0;
11734 if (threadinfo) { /* Thread local storage... */
11735 TlsSetValue(TlsIndex,threadinfo);
11736 debug(F100, "doftpsend2 called with threadinfo block","", 0);
11737 } else debug(F100, "doftpsend2 - threadinfo is NULL", "", 0);
11746 #endif /* CK_LOGIN */
11748 buf = ftpsndbuf; /* (not on stack) */
11750 unique = strcmp(ftpsnd.cmd,"STOU") ? 0 : 1;
11751 notafile = sndarray || pipesend;
11754 if (ftpsnd.restart && ((curtype == FTT_BIN) || (alike > 0))) {
11756 changetype(FTT_BIN,0); /* Change to binary */
11758 /* Ask for remote file's size */
11759 x = ftpcmd("SIZE",ftpsnd.remote,ftpsnd.incs,ftpsnd.outcs,ftp_vbm);
11761 if (x == REPLY_COMPLETE) { /* Have ftpsnd.reply */
11762 p = &ftp_reply_str[4]; /* Parse it */
11763 while (isdigit(*p)) {
11764 sendstart = sendstart * 10 + (int)(*p - '0');
11767 if (*p && *p != CR) { /* Bad number */
11768 debug(F110,"doftpsend2 bad size",ftp_reply_str,0);
11769 sendstart = (CK_OFF_T)0;
11770 } else if (sendstart > fsize) { /* Remote file bigger than local */
11771 debug(F110,"doftpsend2 big size",ckfstoa(fsize),sendstart);
11772 sendstart = (CK_OFF_T)0;
11774 /* Local is newer */
11775 debug(F111,"doftpsend2 size",ftpsnd.remote,sendstart);
11776 if (chkmodtime(ftpsnd.local,ftpsnd.remote,0) == 2) {
11777 debug(F110,"doftpsend2 date mismatch",ftp_reply_str,0);
11778 sendstart = (CK_OFF_T)0; /* Send the whole file */
11781 changetype(ftp_typ,0); /* Change back to appropriate type */
11782 if (sendstart > (CK_OFF_T)0) { /* Still restarting? */
11783 if (sendstart == fsize) { /* Same size - no need to send */
11784 debug(F111,"doftpsend2 /restart SKIP",
11785 ckfstoa(fsize),sendstart);
11787 ftpsndret = SKP_RES;
11789 ckThreadEnd(threadinfo);
11793 errno = 0; /* Restart needed, seek to the spot */
11794 if (zfseek((long)sendstart) < 0) {
11795 debug(F111,"doftpsend2 zfseek fails",
11796 ftpsnd.local,sendstart);
11797 fprintf(stderr, "FSEEK: %s: %s\n", ftpsnd.local, ck_errstr());
11802 ckThreadEnd(threadinfo);
11807 debug(F111,"doftpsend2 zfseek ok",ftpsnd.local,sendstart);
11808 x = ftpcmd("REST",ckltoa(sendstart),-1,-1,ftp_vbm);
11809 if (x != REPLY_CONTINUE) {
11814 ckThreadEnd(threadinfo);
11818 ftpsnd.cmd = "STOR";
11821 sendmode = SM_RESEND;
11822 ftpsnd.cmd = "APPE";
11823 #endif /* COMMENT */
11824 /* sendstart = (CK_OFF_T)0; */
11827 #endif /* FTP_RESTART */
11829 if (unique && !stouarg) /* If we know STOU accepts no arg */
11830 ftpsnd.remote = NULL; /* don't include one. */
11832 x = ftpcmd(ftpsnd.cmd, ftpsnd.remote, ftpsnd.incs, ftpsnd.outcs, ftp_vbm);
11833 debug(F111,"doftpsend2 ftpcode",ftpsnd.cmd,ftpcode);
11834 debug(F101,"doftpsend2 ftpcmd","",x);
11836 if (x != REPLY_PRELIM && unique) {
11838 RFC959 says STOU does not take an argument. But every FTP server
11839 I've encountered but one accepts the arg and constructs the unique
11840 name from it, which is better than making up a totally random name
11841 for the file, which is what RFC959 calls for. Especially because
11842 there is no way for the client to find out the name chosen by the
11843 server. So we try STOU with the argument first, which works with
11844 most servers, and if it fails we retry it without the arg, for
11845 the benefit of the one picky server that is not "liberal in what
11846 it accepts" UNLESS the first STOU got a 502 code ("not implemented")
11847 which means STOU is not accepted, period.
11849 if ((x == 5) && stouarg && (ftpcode != 502)) {
11850 x = ftpcmd(ftpsnd.cmd,NULL,ftpsnd.incs,ftpsnd.outcs,ftp_vbm);
11851 if (x == REPLY_PRELIM) /* If accepted */
11852 stouarg = 0; /* flag no STOU arg for this server */
11855 if (x != REPLY_PRELIM) {
11856 signal(SIGINT, ftpsnd.oldintr);
11858 if (ftpsnd.oldintp)
11859 signal(SIGPIPE, ftpsnd.oldintp);
11860 #endif /* SIGPIPE */
11861 debug(F101,"doftpsend2 not REPLY_PRELIM","",x);
11866 #endif /* PIPESEND */
11869 ckThreadEnd(threadinfo);
11873 debug(F100,"doftpsend2 getting data connection...","",0);
11874 dout = dataconn(ftpsnd.lmode); /* Get data connection */
11875 debug(F101,"doftpsend2 dataconn","",dout);
11877 failftpsend2(threadinfo);
11879 ckThreadEnd(threadinfo);
11883 /* Initialize per-file stats */
11884 ffc = (CK_OFF_T)0; /* Character counter */
11885 cps = oldcps = 0L; /* Thruput */
11888 rftimer(); /* reset f.p. timer */
11889 #endif /* GFTIMER */
11892 ftpsnd.oldintp = signal(SIGPIPE, SIG_IGN);
11893 #endif /* SIGPIPE */
11894 debug(F101,"doftpsend2 curtype","",curtype);
11896 case FTT_BIN: /* Binary mode */
11901 This is because VMS zxin() is C-Library fread()
11902 but the file was opened with zopeni(), which is RMS.
11904 while (((c = zminchar()) > -1) && !cancelfile) {
11906 if (zzout(dout,c) < 0)
11910 while ((n = zxin(ZIFILE,buf,FTP_BUFSIZ - 1)) > 0 && !cancelfile) {
11913 debug(F111,"doftpsend2 zxin",ckltoa(n),ffc);
11914 ckhexdump("doftpsend2 zxin",buf,16);
11916 if (ssl_ftp_data_active_flag) {
11917 for (bufp = buf; n > 0; n -= d, bufp += d) {
11918 if ((d = SSL_write(ssl_ftp_data_con, bufp, n)) <= 0)
11922 if (fdispla != XYFD_B) {
11924 ftscreen(SCR_PT,'D',(CK_OFF_T)spackets,NULL);
11928 #endif /* CK_SSL */
11929 for (bufp = buf; n > 0; n -= d, bufp += d) {
11930 if (((d = secure_write(dout, (CHAR *)bufp, n)) <= 0)
11935 if (fdispla != XYFD_B) {
11937 ftscreen(SCR_PT,'D',(CK_OFF_T)spackets,NULL);
11942 #endif /* CK_SSL */
11948 debug(F111,"doftpsend2 XX zxin",ckltoa(n),ffc);
11950 fprintf(stderr, "local: %s: %s\n", ftpsnd.local, ck_errstr());
11951 if (d < 0 || (d = secure_flush(dout)) < 0) {
11952 if (d == -1 && errno && errno != EPIPE)
11958 case FTT_ASC: /* Text mode */
11960 if (ftpsnd.xlate) { /* With translation */
11961 initxlate(ftpsnd.incs,ftpsnd.outcs);
11962 while (!cancelfile) {
11963 if ((c0 = xgnbyte(FC_UCS2,ftpsnd.incs,NULL)) < 0) break;
11964 if ((x = xpnbyte(c0,TC_UCS2,ftpsnd.outcs,xxout)) < 0) break;
11967 #endif /* NOCSETS */
11968 /* Text mode, no translation */
11969 while (((c = zminchar()) > -1) && !cancelfile) {
11977 #endif /* NOCSETS */
11978 if (dout == -1 || (d = secure_flush(dout)) < 0) {
11979 if (d == -1 && errno && errno != EPIPE)
11985 tfc += ffc; /* Total file chars */
11987 fpfsecs = gftimer();
11988 #endif /* GFTIMER */
11989 zclose(ZIFILE); /* Close input file */
11991 if (sndfilter) /* Undo this (it's per file) */
11993 #endif /* PIPESEND */
11996 if (ssl_ftp_data_active_flag) {
11997 SSL_shutdown(ssl_ftp_data_con);
11998 SSL_free(ssl_ftp_data_con);
11999 ssl_ftp_data_active_flag = 0;
12000 ssl_ftp_data_con = NULL;
12002 #endif /* CK_SSL */
12005 socket_close(dout); /* Close data connection */
12006 #else /* TCPIPLIB */
12007 #ifdef USE_SHUTDOWN
12008 shutdown(dout, 1+1);
12009 #endif /* USE_SHUTDOWN */
12011 #endif /* TCPIPLIB */
12012 ftpsnd.reply = getreply(0,ftpsnd.incs,ftpsnd.outcs,ftp_vbm,0);
12013 signal(SIGINT, ftpsnd.oldintr); /* Put back interrupts */
12015 if (ftpsnd.oldintp)
12016 signal(SIGPIPE, ftpsnd.oldintp);
12017 #endif /* SIGPIPE */
12018 if (ftpsnd.reply == REPLY_TRANSIENT || ftpsnd.reply == REPLY_ERROR) {
12019 debug(F101,"doftpsend2 ftpsnd.reply","",ftpsnd.reply);
12022 ckThreadEnd(threadinfo);
12025 } else if (cancelfile) {
12026 debug(F101,"doftpsend2 canceled","",ftpsnd.bytes);
12029 ckThreadEnd(threadinfo);
12033 debug(F101,"doftpsend2 ok","",ftpsnd.bytes);
12036 ckThreadEnd(threadinfo);
12041 sendrequest(cmd, local, remote, xlate, incs, outcs, restart)
12042 char *cmd, *local, *remote; int xlate, incs, outcs, restart;
12044 if (!remote) remote = ""; /* Check args */
12045 if (!*remote) remote = local;
12046 if (!local) local = "";
12047 if (!*local) return(-1);
12048 if (!cmd) cmd = "";
12049 if (!*cmd) cmd = "STOR";
12051 debug(F111,"ftp sendrequest restart",local,restart);
12053 nout = 0; /* Init output buffer count */
12054 ftpsnd.bytes = 0; /* File input byte count */
12059 proxtrans(cmd, local, remote, !strcmp(cmd,"STOU"));
12062 #endif /* FTP_PROXY */
12064 changetype(ftp_typ,0); /* Change type for this file */
12066 ftpsnd.oldintr = NULL; /* Set up interrupt handler */
12067 ftpsnd.oldintp = NULL;
12068 ftpsnd.restart = restart;
12069 ftpsnd.xlate = xlate;
12070 ftpsnd.lmode = "wb";
12072 #ifdef PIPESEND /* Use Kermit API for file i/o... */
12074 char * p = NULL, * q;
12077 if (cmd_quoting && (p = (char *) malloc(n + 1))) {
12079 debug(F110,"sendrequest pipesend filter",sndfilter,0);
12080 zzstring(sndfilter,&p,&n);
12081 debug(F111,"sendrequest pipename",q,n);
12083 printf("?Sorry, send filter + filename too long, %d max.\n",
12089 ckstrncpy(filnam,q,CKMAXPATH+1);
12096 if (sndfilter) /* If sending thru a filter */
12097 pipesend = 1; /* set this for open and i/o */
12098 #endif /* PIPESEND */
12101 debug(F101,"XXX before openi binary","",binary);
12102 debug(F101,"XXX before openi ftp_typ","",ftp_typ);
12105 if (openi(local) == 0) /* Try to open the input file */
12109 debug(F101,"XXX after openi binary","",binary);
12110 debug(F101,"XXX after openi ftp_typ","",ftp_typ);
12112 if (binary != ftp_typ) { /* VMS zopeni() sets binary */
12113 debug(F101,"XXX changing type","",binary);
12115 debug(F101,"XXX after doftptyp","",ftp_typ);
12118 if (displa && fdispla) { /* Update file type display */
12119 ftscreen(SCR_FN,'F',(CK_OFF_T)0,local);
12125 ftpsnd.incs = incs;
12126 ftpsnd.outcs = outcs;
12128 ftpsnd.local = local;
12129 ftpsnd.remote = remote;
12130 ftpsnd.oldintr = signal(SIGINT, cancelsend);
12133 if (cc_execute(ckjaddr(sendcancel), doftpsend, failftpsend) < 0)
12137 if (cc_execute(ckjaddr(sendcancel), doftpsend2, failftpsend2) < 0)
12144 cancelrecv(sig) int sig; {
12148 secure_getc(0,1); /* Initialize net input buffers */
12149 printf(" Canceling...\n");
12150 debug(F100,"ftp cancelrecv caught SIGINT","",0);
12153 if (fp_nml != stdout)
12158 longjmp(recvcancel, 1);
12164 /* Argumentless front-end for secure_getc() */
12168 return(secure_getc(globaldin,0));
12171 /* Returns -1 on failure, 0 on success, 1 if file skipped */
12174 Sets ftpcode < 0 on failure if failure reason is not server reply code:
12175 -1: interrupted by user.
12176 -2: error opening or writing output file (reason in errno).
12177 -3: failure to make data connection.
12178 -4: network read error (reason in errno).
12181 struct xx_ftprecv {
12189 sig_t oldintr, oldintp;
12196 CK_OFF_T localsize;
12198 static struct xx_ftprecv ftprecv;
12200 static int ftprecvret = 0;
12204 failftprecv(VOID * threadinfo)
12206 failftprecv(threadinfo) VOID * threadinfo;
12207 #endif /* CK_ANSIC */
12210 if (threadinfo) { /* Thread local storage... */
12211 TlsSetValue(TlsIndex,threadinfo);
12212 debug(F100, "docmdfile called with threadinfo block","", 0);
12213 } else debug(F100, "docmdfile - threadinfo is NULL", "", 0);
12223 #endif /* CK_LOGIN */
12226 ftprecv.reply = getreply(0,ftprecv.fcs,ftprecv.rcs,ftp_vbm,0);
12230 if (ssl_ftp_data_active_flag) {
12231 SSL_shutdown(ssl_ftp_data_con);
12232 SSL_free(ssl_ftp_data_con);
12233 ssl_ftp_data_active_flag = 0;
12234 ssl_ftp_data_con = NULL;
12236 #endif /* CK_SSL */
12238 socket_close(data);
12239 #else /* TCPIPLIB */
12240 #ifdef USE_SHUTDOWN
12241 shutdown(data, 1+1);
12242 #endif /* USE_SHUTDOWN */
12244 #endif /* TCPIPLIB */
12248 if (ftprecv.oldintr)
12249 signal(SIGINT, ftprecv.oldintr);
12254 /* TEST ME IN K95 */
12257 debug(F100,"ftp failftprecv chain to trap()...","",0);
12258 if (ftprecv.oldintr != SIG_IGN)
12259 (*ftprecv.oldintr)(SIGINT);
12260 /* NOTREACHED (I hope!) */
12261 debug(F100,"ftp failftprecv return from trap()...","",0);
12269 doftprecv(VOID * threadinfo)
12271 doftprecv(threadinfo) VOID * threadinfo;
12272 #endif /* CK_ANSIC */
12275 if (threadinfo) { /* Thread local storage... */
12276 TlsSetValue(TlsIndex,threadinfo);
12277 debug(F100, "docmdfile called with threadinfo block","", 0);
12278 } else debug(F100, "docmdfile - threadinfo is NULL", "", 0);
12287 #endif /* CK_LOGIN */
12290 if (!out2screen && !ftprecv.pipename) {
12293 local = ftprecv.local;
12296 if ((!dpyactive || ftp_deb))
12298 "Temporary file %s: %s\n", ftprecv.local, ck_errstr());
12299 signal(SIGINT, ftprecv.oldintr);
12303 ckThreadEnd(threadinfo);
12308 #endif /* COMMENT */
12309 changetype((!ftprecv.is_retr) ? FTT_ASC : ftp_typ, 0);
12310 if (initconn()) { /* Initialize the data connection */
12311 signal(SIGINT, ftprecv.oldintr);
12315 ckThreadEnd(threadinfo);
12319 secure_getc(0,1); /* Initialize net input buffers */
12323 ckThreadEnd(threadinfo);
12329 failftprecv2(VOID * threadinfo)
12331 failftprecv2(threadinfo) VOID * threadinfo;
12332 #endif /* CK_ANSIC */
12335 if (threadinfo) { /* Thread local storage... */
12336 TlsSetValue(TlsIndex,threadinfo);
12337 debug(F100, "docmdfile called with threadinfo block","", 0);
12338 } else debug(F100, "docmdfile - threadinfo is NULL", "", 0);
12347 #endif /* CK_LOGIN */
12349 /* Cancel using RFC959 recommended IP,SYNC sequence */
12351 debug(F100,"ftp recvrequest CANCEL","",0);
12353 fpfsecs = gftimer();
12354 #endif /* GFTIMER */
12356 if (ftprecv.oldintp)
12357 signal(SIGPIPE, ftprecv.oldintr);
12358 #endif /* SIGPIPE */
12359 signal(SIGINT, SIG_IGN);
12362 signal(SIGINT, ftprecv.oldintr);
12365 ckThreadEnd(threadinfo);
12369 cancel_remote(ftprecv.din);
12372 if (ftp_timed_out && out2screen && !quiet)
12373 printf("\n?Timed out.\n");
12374 #endif /* FTP_TIMEOUT */
12380 if (ssl_ftp_data_active_flag) {
12381 SSL_shutdown(ssl_ftp_data_con);
12382 SSL_free(ssl_ftp_data_con);
12383 ssl_ftp_data_active_flag = 0;
12384 ssl_ftp_data_con = NULL;
12386 #endif /* CK_SSL */
12388 socket_close(data);
12389 #else /* TCPIPLIB */
12390 #ifdef USE_SHUTDOWN
12391 shutdown(data, 1+1);
12392 #endif /* USE_SHUTDOWN */
12394 #endif /* TCPIPLIB */
12400 debug(F111,"ftp failrecv2 zclose",ftprecv.local,keep);
12402 switch (keep) { /* which is... */
12403 case SET_AUTO: /* AUTO */
12404 if (curtype == FTT_ASC) /* Delete file if TYPE A. */
12407 case SET_OFF: /* DISCARD */
12408 x = 1; /* Delete file, period. */
12410 default: /* KEEP */
12414 x = zdelet(ftprecv.local);
12415 debug(F111,"ftp failrecv2 delete incomplete",ftprecv.local,x);
12420 socket_close(ftprecv.din);
12421 #else /* TCPIPLIB */
12422 #ifdef USE_SHUTDOWN
12423 shutdown(ftprecv.din, 1+1);
12424 #endif /* USE_SHUTDOWN */
12425 close(ftprecv.din);
12426 #endif /* TCPIPLIB */
12428 signal(SIGINT, ftprecv.oldintr);
12433 debug(F100,"FTP failftprecv2 chain to trap()...","",0);
12435 debug(F100,"FTP failftprecv2 PostCtrlCSem()...","",0);
12438 if (ftprecv.oldintr != SIG_IGN)
12439 (*ftprecv.oldintr)(SIGINT);
12440 /* NOTREACHED (I hope!) */
12441 debug(F100,"ftp failftprecv2 return from trap()...","",0);
12448 doftprecv2(VOID * threadinfo)
12450 doftprecv2(threadinfo) VOID * threadinfo;
12451 #endif /* CK_ANSIC */
12454 CK_OFF_T bytes = (CK_OFF_T)0;
12457 ULONG start = 0L, stop;
12459 static char * rcvbuf = NULL;
12460 static int rcvbufsiz = 0;
12462 char newname[CKMAXPATH+1]; /* For file dialog */
12463 #endif /* CK_URL */
12464 extern int adl_ask;
12468 #endif /* FTP_TIMEOUT */
12472 if (threadinfo) { /* Thread local storage... */
12473 TlsSetValue(TlsIndex,threadinfo);
12474 debug(F100, "docmdfile called with threadinfo block","", 0);
12475 } else debug(F100, "docmdfile - threadinfo is NULL", "", 0);
12484 #endif /* CK_LOGIN */
12486 if (ftprecv.recover) { /* Initiate recovery */
12487 x = ftpcmd("REST",ckfstoa(ftprecv.localsize),-1,-1,ftp_vbm);
12488 debug(F111,"ftp reply","REST",x);
12489 if (x == REPLY_CONTINUE) {
12490 ftprecv.lmode = "ab";
12491 rs_len = ftprecv.localsize;
12493 ftprecv.recover = 0;
12496 /* IMPORTANT: No FTP commands can come between REST and RETR! */
12498 debug(F111,"ftp recvrequest recover E",ftprecv.remote,ftprecv.recover);
12500 /* Send the command and get reply */
12501 debug(F110,"ftp recvrequest cmd",ftprecv.cmd,0);
12502 debug(F110,"ftp recvrequest remote",ftprecv.remote,0);
12504 if (ftpcmd(ftprecv.cmd,ftprecv.remote,ftprecv.fcs,ftprecv.rcs,ftp_vbm)
12506 signal(SIGINT, ftprecv.oldintr); /* Bad reply, fail. */
12507 ftprecvret = -1; /* ftpcode is set by ftpcmd() */
12509 ckThreadEnd(threadinfo);
12513 ftprecv.din = dataconn("r"); /* Good reply, open data connection */
12514 globaldin = ftprecv.din; /* Global copy of file descriptor */
12515 if (ftprecv.din == -1) { /* Check for failure */
12516 ftpcode = -3; /* Code for no data connection */
12519 ckThreadEnd(threadinfo);
12524 /* In K95 GUI put up a file box */
12525 if (haveurl && g_url.pth && adl_ask ) { /* Downloading from a URL */
12528 "\r\nIncoming file from FTP server...\r\n\
12529 Please confirm output file specification or supply an alternative:";
12531 x = uq_file(preface, /* K95 GUI: Put up file box. */
12535 ftprecv.local ? ftprecv.local : ftprecv.remote,
12540 ftprecv.local = newname; /* Substitute user's file name */
12541 if (x == 2) /* And append if user said to */
12542 ftprecv.lmode = "ab";
12545 #endif /* CK_URL */
12546 x = 1; /* Output file open OK? */
12547 if (ftprecv.pipename) { /* Command */
12548 x = zxcmd(ZOFILE,ftprecv.pipename);
12549 debug(F111,"ftp recvrequest zxcmd",ftprecv.pipename,x);
12550 } else if (!out2screen) { /* File */
12552 xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
12553 xx.typ = 0; xx.os_specific = NUL; xx.lblopts = 0;
12554 /* Append or New */
12555 xx.dsp = !strcmp(ftprecv.lmode,"ab") ? XYFZ_A : XYFZ_N;
12556 x = zopeno(ZOFILE,ftprecv.local,NULL,&xx);
12557 debug(F111,"ftp recvrequest zopeno",ftprecv.local,x);
12559 if (x < 1) { /* Failure to open output file */
12560 if ((!dpyactive || ftp_deb))
12561 fprintf(stderr, "local(2): %s: %s\n", ftprecv.local, ck_errstr());
12564 ckThreadEnd(threadinfo);
12568 blksize = FTP_BUFSIZ; /* Allocate input buffer */
12570 debug(F101,"ftp recvrequest blksize","",blksize);
12571 debug(F101,"ftp recvrequest rcvbufsiz","",rcvbufsiz);
12573 if (rcvbufsiz < blksize) { /* if necessary */
12578 rcvbuf = (char *)malloc((unsigned)blksize);
12580 debug(F100,"ftp get rcvbuf malloc failed","",0);
12584 #endif /* ENOMEM */
12585 if ((!dpyactive || ftp_deb))
12590 ckThreadEnd(threadinfo);
12594 debug(F101,"ftp get rcvbuf malloc ok","",blksize);
12595 rcvbufsiz = blksize;
12597 debug(F111,"ftp get rcvbufsiz",ftprecv.local,rcvbufsiz);
12599 ffc = (CK_OFF_T)0; /* Character counter */
12600 cps = oldcps = 0L; /* Thruput */
12601 start = gmstimer(); /* Start time (msecs) */
12603 rftimer(); /* Start time (float) */
12604 #endif /* GFTIMER */
12606 debug(F111,"ftp get type",ftprecv.local,curtype);
12607 debug(F101,"ftp recvrequest ftp_dpl","",ftp_dpl);
12609 case FTT_BIN: /* Binary mode */
12610 case FTT_TEN: /* TENEX mode */
12614 c = secure_read(ftprecv.din, rcvbuf, rcvbufsiz);
12616 failftprecv2(threadinfo);
12618 ckThreadEnd(threadinfo);
12624 #ifdef printf /* (What if it isn't?) */
12625 if (out2screen && !ftprecv.pipename) {
12627 for (i = 0; i < c; i++)
12628 printf("%c",rcvbuf[i]);
12630 #endif /* printf */
12636 if (zmchout(rcvbuf[i++]) < 0) {
12647 debug(F100,"ftp recvrequest timeout","",0);
12648 bytes = (CK_OFF_T)-1;
12652 #endif /* FTP_TIMEOUT */
12654 debug(F111,"ftp recvrequest errno",ckitoa(c),errno);
12655 if (c == -1 && errno != EPIPE)
12656 if ((!dpyactive || ftp_deb))
12658 bytes = (CK_OFF_T)-1;
12663 if ((!dpyactive || ftp_deb)) {
12665 p = ftprecv.local ? ftprecv.local : ftprecv.pipename;
12668 "local(3): %s: %s\n", ftprecv.local, ck_errstr());
12671 "%s: short write\n", ftprecv.local);
12676 case FTT_ASC: /* Text mode */
12677 debug(F101,"ftp recvrequest TYPE A xlate","",ftprecv.xlate);
12679 if (ftprecv.xlate) {
12685 #endif /* CK_ANSIC */
12686 debug(F110,"ftp recvrequest (data)","initxlate",0);
12687 initxlate(ftprecv.rcs,ftprecv.fcs); /* (From,To) */
12688 if (ftprecv.pipename) {
12690 debug(F110,"ftp recvrequest ASCII","pipeout",0);
12692 fn = out2screen ? scrnout : putfil;
12693 debug(F110,"ftp recvrequest ASCII",
12694 out2screen ? "scrnout" : "putfil",0);
12697 /* Get byte from net */
12698 c0 = xgnbyte(FC_UCS2,ftprecv.rcs,netgetc);
12700 failftprecv2(threadinfo);
12702 ckThreadEnd(threadinfo);
12708 /* Second byte from net */
12709 c1 = xgnbyte(FC_UCS2,ftprecv.rcs,netgetc);
12711 failftprecv2(threadinfo);
12713 ckThreadEnd(threadinfo);
12720 /* K95: Check whether we need this */
12721 if (fileorder > 0) /* Little Endian */
12722 bytswap(&c0,&c1); /* swap bytes*/
12723 #endif /* COMMENT */
12726 if ( out2screen && /* we're translating to UCS-2 */
12727 !k95stdout && !inserver) /* for the real screen... */
12734 output.bytes[0] = c1;
12735 output.bytes[1] = c0;
12737 VscrnWrtUCS2StrAtt(VCMD,
12748 if ((x = xpnbyte(c0,TC_UCS2,ftprecv.fcs,fn)) < 0) break;
12749 if ((x = xpnbyte(c1,TC_UCS2,ftprecv.fcs,fn)) < 0) break;
12753 #endif /* NOCSETS */
12755 c = secure_getc(ftprecv.din,0);
12759 #endif /* FTP_TIMEOUT */
12761 failftprecv2(threadinfo);
12763 ckThreadEnd(threadinfo);
12767 if (c < 0 || c == EOF)
12770 /* Record format conversion for Unix */
12771 /* SKIP THIS FOR WINDOWS! */
12774 while (c == '\r') {
12776 if ((c = secure_getc(ftprecv.din,0)) != '\n' ||
12779 failftprecv2(threadinfo);
12781 ckThreadEnd(threadinfo);
12785 if (c < 0 || c == EOF)
12797 if (out2screen && !ftprecv.pipename)
12799 printf("%c",(char)c);
12802 #endif /* printf */
12804 if ((d = zmchout(c)) < 0)
12812 if (bare_lfs && (!dpyactive || ftp_deb)) {
12813 printf("WARNING! %d bare linefeeds received in ASCII mode\n",
12815 printf("File might not have transferred correctly.\n");
12817 if (ftprecv.din == -1) {
12818 bytes = (CK_OFF_T)-1;
12821 bytes = (CK_OFF_T)-1;
12825 #endif /* NOCSETS */
12827 if (ftprecv.pipename || !out2screen) {
12828 zclose(ZOFILE); /* Close the file */
12829 debug(F111,"doftprecv2 zclose ftpcode",ftprecv.local,ftpcode);
12830 if (ftpcode < 0) { /* If download failed */
12832 switch (keep) { /* which is... */
12833 case SET_AUTO: /* AUTO */
12834 if (curtype == FTT_ASC) /* Delete file if TYPE A. */
12837 case SET_OFF: /* DISCARD */
12838 x = 1; /* Delete file, period. */
12840 default: /* KEEP */
12844 x = zdelet(ftprecv.local);
12845 debug(F111,"ftp get delete incomplete",ftprecv.local,x);
12849 signal(SIGINT, ftprecv.oldintr);
12851 if (ftprecv.oldintp)
12852 signal(SIGPIPE, ftprecv.oldintp);
12853 #endif /* SIGPIPE */
12856 fpfsecs = gftimer();
12857 #endif /* GFTIMER */
12861 socket_close(ftprecv.din);
12862 #else /* TCPIPLIB */
12863 #ifdef USE_SHUTDOWN
12864 shutdown(ftprecv.din, 1+1);
12865 #endif /* USE_SHUTDOWN */
12866 close(ftprecv.din);
12867 #endif /* TCPIPLIB */
12868 ftprecv.reply = getreply(0,ftprecv.fcs,ftprecv.rcs,ftp_vbm,0);
12869 ftprecvret = ((ftpcode < 0 || ftprecv.reply == REPLY_TRANSIENT ||
12870 ftprecv.reply == REPLY_ERROR) ? -1 : 0);
12872 ckThreadEnd(threadinfo);
12877 recvrequest(cmd, local, remote, lmode, printnames, recover, pipename,
12879 char *cmd, *local, *remote, *lmode, *pipename;
12880 int printnames, recover, xlate, fcs, rcs;
12883 struct _stat stbuf;
12890 debug(F111,"ftp recvrequest cmd",cmd,recover);
12891 debug(F110,"ftp recvrequest local ",local,0);
12892 debug(F111,"ftp recvrequest remote",remote,ftp_typ);
12893 debug(F110,"ftp recvrequest pipename ",pipename,0);
12894 debug(F101,"ftp recvrequest xlate","",xlate);
12895 debug(F101,"ftp recvrequest fcs","",fcs);
12896 debug(F101,"ftp recvrequest rcs","",rcs);
12900 ftprecv.localsize = (CK_OFF_T)0;
12902 if (remfile) { /* See remcfm(), remtxt() */
12904 pipename = remdest;
12907 if (remappd) lmode = "ab";
12911 if (!cmd) cmd = ""; /* Core dump prevention */
12912 if (!remote) remote = "";
12913 if (!lmode) lmode = "";
12915 if (pipename) { /* No recovery for pipes. */
12920 if (!local) /* Output to screen? */
12922 out2screen = !strcmp(local,"-");
12924 debug(F101,"ftp recvrequest out2screen","",out2screen);
12927 if ( ftp_xla && out2screen && !k95stdout && !inserver )
12931 if (out2screen) /* No recovery to screen */
12933 if (!ftp_typ) /* No recovery in text mode */
12935 ftprecv.is_retr = (strcmp(cmd, "RETR") == 0);
12937 if (!ftprecv.is_retr) /* No recovery except for RETRieve */
12941 if (!out2screen && !pipename && ftprecv.is_retr) { /* To real file */
12942 if (recursive && ckstrchr(local,'/')) {
12946 #endif /* COMMENT */
12948 ftprecv.localsize = (CK_OFF_T)0; /* Local file size */
12949 rs_len = (CK_OFF_T)0; /* Recovery point */
12951 debug(F101,"ftp recvrequest recover","",recover);
12952 if (recover) { /* Recovering... */
12953 if (stat(local, &stbuf) < 0) { /* Can't stat local file */
12954 debug(F101,"ftp recvrequest recover stat failed","",errno);
12955 recover = 0; /* So cancel recovery */
12956 } else { /* Have local file info */
12957 ftprecv.localsize = stbuf.st_size; /* Get size */
12958 /* Remote file smaller than local */
12959 if (fsize < ftprecv.localsize) {
12960 debug(F101,"ftp recvrequest recover remote smaller","",fsize);
12961 recover = 0; /* Recovery can't work */
12962 } else if (fsize == ftprecv.localsize) { /* Sizes are equal */
12963 debug(F111,"ftp recvrequest recover equal size",
12964 remote,ftprecv.localsize);
12969 The problem here is that the original partial file never got its date
12970 set, either because FTP DATES was OFF, or because the partial file was
12971 downloaded by some other program that doesn't set local file dates, or
12972 because Kermit only sets the file's date when the download was complete
12973 and successful. In all these cases, the local file has a later time
12976 if (recover) { /* Remote is bigger */
12977 x = chkmodtime(local,remote,0); /* Check file dates */
12978 debug(F111,"ftp recvrequest chkmodtime",remote,x);
12979 if (x != 1) /* Dates must be equal! */
12980 recover = 0; /* If not, get whole file */
12982 #endif /* COMMENT */
12984 debug(F111,"ftp recvrequest recover",remote,recover);
12988 if (proxy && ftprecv.is_retr)
12989 return(proxtrans(cmd, local ? local : remote, remote));
12990 #endif /* FTP_PROXY */
12992 ftprecv.tcrflag = (feol != CR) && ftprecv.is_retr;
12997 ftprecv.recover = recover;
12998 ftprecv.xlate = xlate;
13000 ftprecv.local = local;
13001 ftprecv.remote = remote;
13002 ftprecv.lmode = lmode;
13003 ftprecv.pipename = pipename;
13004 ftprecv.oldintp = NULL;
13008 ftprecv.oldintr = signal(SIGINT, cancelrecv);
13009 if (cc_execute(ckjaddr(recvcancel), doftprecv, failftprecv) < 0)
13013 debug(F111,"ftp recvrequest ftprecvret",remote,ftprecvret);
13014 debug(F111,"ftp recvrequest ftp_timed_out",remote,ftp_timed_out);
13017 #endif /* FTP_TIMEOUT */
13019 if (ftprecvret < 0)
13022 if (cc_execute(ckjaddr(recvcancel), doftprecv2, failftprecv2) < 0)
13028 * Need to start a listen on the data channel before we send the command,
13029 * otherwise the server's connect may fail.
13033 register char *p, *a;
13034 int result, tmpno = 0;
13038 #ifndef NO_PASSIVE_MODE
13039 int a1,a2,a3,a4,p1,p2;
13042 data = socket(AF_INET, SOCK_STREAM, 0);
13045 perror("ftp: socket");
13048 if (ftpcmd("PASV",NULL,0,0,ftp_vbm) != REPLY_COMPLETE) {
13049 printf("Passive mode refused\n");
13051 return(initconn());
13054 Now we have a string of comma-separated one-byte unsigned integer values,
13055 The first four are the an IP address. The fifth is the MSB of the port
13056 number, the sixth is the LSB. From that we can make a sockaddr_in.
13058 if (sscanf(pasv,"%d,%d,%d,%d,%d,%d",&a1,&a2,&a3,&a4,&p1,&p2) != 6) {
13059 printf("Passive mode address scan failure\n");
13063 if (tcp_http_proxy) {
13065 char * agent = "Kermit 95"; /* Default user agent */
13067 char * agent = "C-Kermit";
13069 register struct hostent *hp = 0;
13070 struct servent *destsp;
13071 char host[512], *p, *q;
13073 #ifdef IPTOS_THROUGHPUT
13075 #endif /* IPTOS_THROUGHPUT */
13076 #endif /* IP_TOS */
13085 ckmakxmsg(proxyhost,HTTPCPYL,ckuitoa(a1),".",ckuitoa(a2),
13086 ".",ckuitoa(a3),".",ckuitoa(a4),":",ckuitoa((p1<<8)|p2),
13089 memset((char *)&hisctladdr, 0, sizeof (hisctladdr));
13090 for (p = tcp_http_proxy, q=host; *p != '\0' && *p != ':'; p++, q++)
13094 hisctladdr.sin_addr.s_addr = inet_addr(host);
13095 if (hisctladdr.sin_addr.s_addr != INADDR_NONE) /* 2010-03-29 */
13097 debug(F110,"initconn A",host,0);
13098 hisctladdr.sin_family = AF_INET;
13100 debug(F110,"initconn B",host,0);
13101 hp = gethostbyname(host);
13103 hp = ck_copyhostent(hp); /* make safe copy that won't change */
13104 #endif /* HADDRLIST */
13106 fprintf(stderr, "ftp: %s: Unknown host\n", host);
13113 hisctladdr.sin_family = hp->h_addrtype;
13115 memcpy((char *)&hisctladdr.sin_addr, hp->h_addr_list[0],
13116 sizeof(hisctladdr.sin_addr));
13117 #else /* HADDRLIST */
13118 memcpy((char *)&hisctladdr.sin_addr, hp->h_addr,
13119 sizeof(hisctladdr.sin_addr));
13120 #endif /* HADDRLIST */
13122 data = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
13123 debug(F101,"initconn socket","",data);
13125 perror("ftp: socket");
13137 destsp = getservbyname(p,"tcp");
13139 hisctladdr.sin_port = destsp->s_port;
13141 hisctladdr.sin_port = htons(atoi(p));
13143 hisctladdr.sin_port = htons(80);
13146 debug(F100,"initconn HADDRLIST","",0);
13149 debug(F100,"initconn no HADDRLIST","",0);
13151 #endif /* HADDRLIST */
13152 (connect(data, (struct sockaddr *)&hisctladdr,
13153 sizeof (hisctladdr)) < 0) {
13154 debug(F101,"initconn connect failed","",errno);
13156 if (hp && hp->h_addr_list[1]) {
13157 int oerrno = errno;
13160 "ftp: connect to address %s: ",
13161 inet_ntoa(hisctladdr.sin_addr)
13166 memcpy((char *)&hisctladdr.sin_addr,
13167 hp->h_addr_list[0],
13168 sizeof(hisctladdr.sin_addr));
13169 fprintf(stdout, "Trying %s...\n",
13170 inet_ntoa(hisctladdr.sin_addr));
13172 socket_close(data);
13173 #else /* TCPIPLIB */
13175 #endif /* TCPIPLIB */
13176 data = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
13178 perror("ftp: socket");
13187 #endif /* HADDRLIST */
13188 perror("ftp: connect");
13192 if (http_connect(data,
13193 tcp_http_proxy_agent ?
13194 tcp_http_proxy_agent :
13197 tcp_http_proxy_user,
13198 tcp_http_proxy_pwd,
13203 socket_close(data);
13204 #else /* TCPIPLIB */
13206 #endif /* TCPIPLIB */
13207 perror("ftp: connect");
13212 #endif /* NOHTTP */
13214 data_addr.sin_family = AF_INET;
13215 data_addr.sin_addr.s_addr = htonl((a1<<24)|(a2<<16)|(a3<<8)|a4);
13216 data_addr.sin_port = htons((p1<<8)|p2);
13219 (struct sockaddr *)&data_addr,
13220 sizeof(data_addr)) < 0
13222 perror("ftp: connect");
13226 debug(F100,"initconn connect ok","",0);
13228 #ifdef IPTOS_THROUGHPUT
13229 on = IPTOS_THROUGHPUT;
13230 if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
13231 perror("ftp: setsockopt TOS (ignored)");
13232 #endif /* IPTOS_THROUGHPUT */
13233 #endif /* IP_TOS */
13234 memcpy(&hisdataaddr,&data_addr,sizeof(struct sockaddr_in));
13237 #endif /* NO_PASSIVE_MODE */
13240 memcpy(&data_addr,&myctladdr,sizeof(struct sockaddr_in));
13242 data_addr.sin_port = 0; /* let system pick one */
13245 socket_close(data);
13246 #else /* TCPIPLIB */
13247 #ifdef USE_SHUTDOWN
13248 shutdown(data, 1+1);
13249 #endif /* USE_SHUTDOWN */
13251 #endif /* TCPIPLIB */
13253 data = socket(AF_INET, SOCK_STREAM, 0);
13256 perror("ftp: socket");
13262 if (setsockopt(data,
13269 perror("ftp: setsockopt (reuse address)");
13273 if (bind(data, (struct sockaddr *)&data_addr, sizeof (data_addr)) < 0) {
13274 perror("ftp: bind");
13277 len = sizeof (data_addr);
13278 if (getsockname(data, (struct sockaddr *)&data_addr, &len) < 0) {
13279 perror("ftp: getsockname");
13282 if (listen(data, 1) < 0) {
13283 perror("ftp: listen");
13287 a = (char *)&data_addr.sin_addr;
13288 p = (char *)&data_addr.sin_port;
13289 ckmakxmsg(ftpcmdbuf,FTP_BUFSIZ,"PORT ",
13290 UC(a[0]),",",UC(a[1]),",", UC(a[2]),",", UC(a[3]),",",
13291 UC(p[0]),",", UC(p[1]));
13292 result = ftpcmd(ftpcmdbuf,NULL,0,0,ftp_vbm);
13293 if (result == REPLY_ERROR && sendport) {
13298 return(result != REPLY_COMPLETE);
13303 #ifdef IPTOS_THROUGHPUT
13304 on = IPTOS_THROUGHPUT;
13305 if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
13306 perror("ftp: setsockopt TOS (ignored)");
13312 socket_close(data);
13313 #else /* TCPIPLIB */
13314 #ifdef USE_SHUTDOWN
13315 shutdown(data, 1+1);
13316 #endif /* USE_SHUTDOWN */
13318 #endif /* TCPIPLIB */
13329 if (ssl_ftp_data_con!=NULL) { /* Do SSL */
13330 SSL_free(ssl_ftp_data_con);
13331 ssl_ftp_data_con=NULL;
13333 ssl_ftp_data_con=(SSL *)SSL_new(ssl_ftp_ctx);
13335 SSL_set_fd(ssl_ftp_data_con,data);
13336 SSL_set_verify(ssl_ftp_data_con,ssl_verify_flag,NULL);
13338 SSL_copy_session_id(ssl_ftp_data_con,ssl_ftp_con);
13340 if (ssl_debug_flag) {
13341 fprintf(stderr,"=>START SSL connect on DATA\n");
13344 if (SSL_connect(ssl_ftp_data_con) <= 0) {
13345 static char errbuf[1024];
13346 ckmakmsg(errbuf,1024,"ftp: SSL_connect DATA error: ",
13347 ERR_error_string(ERR_get_error(),NULL),NULL,NULL);
13348 fprintf(stderr,"%s\n", errbuf);
13351 socket_close(data);
13352 #else /* TCPIPLIB */
13353 #ifdef USE_SHUTDOWN
13354 shutdown(data, 1+1);
13355 #endif /* USE_SHUTDOWN */
13357 #endif /* TCPIPLIB */
13362 ssl_ftp_data_active_flag=1;
13364 if (!ssl_certsok_flag && !tls_is_krb5(2)) {
13365 char *subject = ssl_get_subject_name(ssl_ftp_data_con);
13368 if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
13369 debug(F110,"dataconn","[SSL _- FAILED]",0);
13371 ssl_ftp_data_active_flag = 0;
13373 socket_close(data);
13374 #else /* TCPIPLIB */
13375 #ifdef USE_SHUTDOWN
13376 shutdown(data, 1+1);
13377 #endif /* USE_SHUTDOWN */
13379 #endif /* TCPIPLIB */
13384 if (!out2screen && displa && fdispla) {
13385 ftscreen(SCR_TC,0,(CK_OFF_T)0,"Display canceled");
13386 /* fdispla = XYFD_B; */
13390 "Warning: Server didn't provide a certificate on data connection\n",
13391 "Continue with file transfer? (Y/N)",
13393 debug(F110, "dataconn","[SSL - FAILED]",0);
13394 ssl_ftp_data_active_flag = 0;
13396 socket_close(data);
13397 #else /* TCPIPLIB */
13398 #ifdef USE_SHUTDOWN
13399 shutdown(data, 1+1);
13400 #endif /* USE_SHUTDOWN */
13402 #endif /* TCPIPLIB */
13409 if (!out2screen && displa && fdispla == XYFD_C) {
13410 ftscreen(SCR_TC,0,(CK_OFF_T)0,"Display canceled");
13411 /* fdispla = XYFD_B; */
13414 if (ssl_check_server_name(ssl_ftp_data_con,ftp_user_host)) {
13415 debug(F110,"dataconn","[SSL - FAILED]",0);
13416 ssl_ftp_data_active_flag = 0;
13418 socket_close(data);
13419 #else /* TCPIPLIB */
13420 #ifdef USE_SHUTDOWN
13421 shutdown(data, 1+1);
13422 #endif /* USE_SHUTDOWN */
13424 #endif /* TCPIPLIB */
13431 debug(F110,"dataconn","[SSL - OK]",0);
13433 /* This messes up the full screen file transfer display */
13434 ssl_display_connect_details(ssl_ftp_con,0,ssl_verbose_flag);
13435 #endif /* COMMENT */
13437 if (ssl_debug_flag) {
13438 fprintf(stderr,"=>DONE SSL connect on DATA\n");
13443 #endif /* CK_SSL */
13446 dataconn(lmode) char *lmode; {
13450 #endif /* IP_TOS */
13452 static u_int fromlen;
13454 static SOCKOPT_T fromlen;
13457 fromlen = sizeof(hisdataaddr);
13459 #ifndef NO_PASSIVE_MODE
13462 ssl_ftp_data_active_flag=0;
13463 if (ssl_ftp_active_flag &&
13464 (ssl_ftp_proxy || ftp_dpl == FPL_PRV))
13465 return(ssl_dataconn());
13466 #endif /* CK_SSL */
13469 #endif /* NO_PASSIVE_MODE */
13471 s = accept(data, (struct sockaddr *) &hisdataaddr, &fromlen);
13473 perror("ftp: accept");
13475 socket_close(data);
13476 #else /* TCPIPLIB */
13477 #ifdef USE_SHUTDOWN
13478 shutdown(data, 1+1);
13479 #endif /* USE_SHUTDOWN */
13481 #endif /* TCPIPLIB */
13487 socket_close(data);
13488 #else /* TCPIPLIB */
13489 #ifdef USE_SHUTDOWN
13490 shutdown(data, 1+1);
13491 #endif /* USE_SHUTDOWN */
13493 #endif /* TCPIPLIB */
13497 #ifdef IPTOS_THROUGHPUT
13498 tos = IPTOS_THROUGHPUT;
13499 if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
13500 perror("ftp: setsockopt TOS (ignored)");
13501 #endif /* IPTOS_THROUGHPUT */
13502 #endif /* IP_TOS */
13505 ssl_ftp_data_active_flag=0;
13506 if (ssl_ftp_active_flag &&
13507 (ssl_ftp_proxy || ftp_dpl == FPL_PRV))
13508 return(ssl_dataconn());
13509 #endif /* CK_SSL */
13515 pscancel(sig) int sig; {
13520 pswitch(flag) int flag; {
13523 static struct comvars {
13525 char name[MAXHOSTNAMELEN];
13526 struct sockaddr_in mctl;
13527 struct sockaddr_in hctl;
13540 char mi[CKMAXPATH];
13541 char mo[CKMAXPATH];
13546 des_cblock session;
13547 des_key_schedule ftp_sched;
13548 #endif /* FTP_KRB4 */
13550 gss_ctx_id_t gcontext;
13551 #endif /* GSSAPI */
13552 } proxstruct, tmpstruct;
13553 struct comvars *ip, *op;
13556 oldintr = signal(SIGINT, pscancel);
13570 ip->connect = connected;
13571 connected = op->connect;
13573 strncpy(ip->name, ftp_host, MAXHOSTNAMELEN - 1);
13574 ip->name[MAXHOSTNAMELEN - 1] = '\0';
13575 ip->name[strlen(ip->name)] = '\0';
13578 ftp_host = op->name;
13579 ip->hctl = hisctladdr;
13580 hisctladdr = op->hctl;
13581 ip->mctl = myctladdr;
13582 myctladdr = op->mctl;
13589 ip->curtpe = curtype;
13590 curtype = op->curtpe;
13593 ip->sunqe = ftp_usn;
13594 ftp_usn = op->sunqe;
13597 ip->ntflg = ntflag;
13598 ntflag = op->ntflg;
13599 strncpy(ip->nti, ntin, 16);
13600 (ip->nti)[strlen(ip->nti)] = '\0';
13601 strcpy(ntin, op->nti);
13602 strncpy(ip->nto, ntout, 16);
13603 (ip->nto)[strlen(ip->nto)] = '\0';
13604 strcpy(ntout, op->nto);
13605 ip->mapflg = mapflag;
13606 mapflag = op->mapflg;
13607 strncpy(ip->mi, mapin, CKMAXPATH - 1);
13608 (ip->mi)[strlen(ip->mi)] = '\0';
13609 strcpy(mapin, op->mi);
13610 strncpy(ip->mo, mapout, CKMAXPATH - 1);
13611 (ip->mo)[strlen(ip->mo)] = '\0';
13612 strcpy(mapout, op->mo);
13613 ip->authtype = auth_type;
13614 auth_type = op->authtype;
13615 ip->clvl = ftp_cpl;
13616 ftp_cpl = op->clvl;
13617 ip->dlvl = ftp_dpl;
13618 ftp_dpl = op->dlvl;
13624 memcpy(ip->session, ftp_cred.session, sizeof(ftp_cred.session));
13625 memcpy(ftp_cred.session, op->session, sizeof(ftp_cred.session));
13626 memcpy(ip->schedule, ftp_sched, sizeof(ftp_sched));
13627 memcpy(ftp_sched, op->schedule, sizeof(ftp_sched));
13628 #endif /* FTP_KRB4 */
13630 ip->gcontext = gcontext;
13631 gcontext = op->gcontext;
13632 #endif /* GSSAPI */
13633 signal(SIGINT, oldintr);
13636 debug(F101,"pswitch cancelfile B","",cancelfile);
13637 (*oldintr)(SIGINT);
13642 cancelpt(sig) int sig; {
13648 longjmp(ptcancel, 1);
13655 proxtrans(cmd, local, remote, unique) char *cmd, *local, *remote; int unique; {
13657 int secndflag = 0, prox_type, nfnd;
13661 #endif /* BSDSELECT */
13662 sigtype cancelpt();
13664 if (strcmp(cmd, "RETR"))
13667 cmd2 = unique ? "STOU" : "STOR";
13668 if ((prox_type = type) == 0) {
13669 if (servertype == SYS_UNIX && unix_proxy)
13670 prox_type = FTT_BIN;
13672 prox_type = FTT_ASC;
13674 if (curtype != prox_type)
13675 changetype(prox_type, 1);
13676 if (ftpcmd("PASV",NULL,0,0,ftp_vbm) != REPLY_COMPLETE) {
13677 printf("Proxy server does not support third party transfers.\n");
13682 printf("No primary connection\n");
13687 if (curtype != prox_type)
13688 changetype(prox_type, 1);
13690 if (ftpcmd("PORT",pasv,-1,-1,ftp_vbm) != REPLY_COMPLETE) {
13695 /* Replace with calls to cc_execute() */
13696 if (setjmp(ptcancel))
13698 oldintr = signal(SIGINT, cancelpt);
13699 if (ftpcmd(cmd,remote,-1,-1,ftp_vbm) != PRELIM) {
13700 signal(SIGINT, oldintr);
13707 if (ftpcmd(cmd2,local,-1,-1,ftp_vbm) != PRELIM)
13710 getreply(0,-1,-1,ftp_vbm,0);
13712 getreply(0,-1,-1,ftp_vbm,0);
13713 signal(SIGINT, oldintr);
13719 signal(SIGINT, SIG_IGN);
13721 if (strcmp(cmd, "RETR") && !proxy)
13723 else if (!strcmp(cmd, "RETR") && proxy)
13725 if (!cpend && !secndflag) { /* only here if cmd = "STOR" (proxy=1) */
13726 if (ftpcmd(cmd2,local,-1,-1,ftp_vbm) != PRELIM) {
13734 signal(SIGINT, oldintr);
13740 if (!cpend && !secndflag) { /* only if cmd = "RETR" (proxy=1) */
13741 if (ftpcmd(cmd2,local,-1,-1,ftp_vbm) != PRELIM) {
13748 signal(SIGINT, oldintr);
13758 FD_SET(csocket, &mask);
13759 if ((nfnd = empty(&mask, 10)) <= 0) {
13767 #else /* BSDSELECT */
13769 if ((nfnd = empty(&csocket, 1, 10)) <= 0) {
13777 #endif /* IBMSELECT */
13778 #endif /* BSDSELECT */
13779 getreply(0,-1,-1,ftp_vbm,0);
13780 getreply(0,-1,-1,ftp_vbm,0);
13787 signal(SIGINT, oldintr);
13789 #endif /* FTP_PROXY */
13791 #ifdef FTP_SECURITY
13795 /* ck_gss_mech_krb5 is not declared anywhere */
13797 CONST gss_OID_desc * CONST * mech_type;
13798 char *service_name;
13800 { &ck_gss_mech_krb5, "ftp" },
13801 { &ck_gss_mech_krb5, "host" },
13804 /* This matches what is declared above */
13806 CONST gss_OID_desc * CONST * mech_type;
13807 char *service_name;
13809 { &gss_mech_krb5, "ftp" },
13810 { &gss_mech_krb5, "host" },
13812 #endif /* COMMENT */
13815 int n_gss_trials = sizeof(gss_trials)/sizeof(gss_trials[0]);
13816 #endif /* FTP_GSSAPI */
13820 extern int setsafe();
13823 char *service, inst[INST_SZ];
13825 ULONG checksum = (ULONG) getpid();
13826 CHAR out_buf[FTP_BUFSIZ];
13828 #else /* FTP_KRB4 */
13830 CHAR out_buf[FTP_BUFSIZ];
13832 #endif /* FTP_GSSAPI */
13833 #endif /* FTP_KRB4 */
13835 if (ssl_ftp_proxy) /* Do not allow AUTH over SSL proxy */
13839 return(1); /* auth already succeeded */
13841 /* Try each auth type as specified by the end user */
13842 for (j = 0; j < 8 && ftp_auth_type[j] != 0; j++) {
13844 if (ftp_auth_type[j] == FTA_GK5 && ck_gssapi_is_installed()) {
13845 n = ftpcmd("AUTH GSSAPI",NULL,0,0,ftp_vbm);
13846 if (n == REPLY_CONTINUE) {
13847 OM_uint32 maj_stat, min_stat;
13848 gss_name_t target_name;
13849 gss_buffer_desc send_tok, recv_tok, *token_ptr;
13850 char stbuf[FTP_BUFSIZ];
13851 int comcode, trial;
13852 struct gss_channel_bindings_struct chan;
13853 char * realm = NULL;
13856 chan.initiator_addrtype = GSS_C_AF_INET; /* OM_uint32 */
13857 chan.initiator_address.length = 4;
13858 chan.initiator_address.value = &myctladdr.sin_addr.s_addr;
13859 chan.acceptor_addrtype = GSS_C_AF_INET; /* OM_uint32 */
13860 chan.acceptor_address.length = 4;
13861 chan.acceptor_address.value = &hisctladdr.sin_addr.s_addr;
13862 chan.application_data.length = 0;
13863 chan.application_data.value = 0;
13866 printf("GSSAPI accepted as authentication type\n");
13868 realm = ck_krb5_realmofhost(ftp_user_host);
13870 ckmakmsg(tgt,sizeof(tgt),"krbtgt/",realm,"@",realm);
13871 debug(F110,"ftp_auth(GSSAPI) TGT",tgt,0);
13872 if ( krb5_autoget &&
13873 !((ck_krb5_tkt_isvalid(NULL,tgt) > 0) ||
13874 (ck_krb5_is_tgt_valid() > 0)) )
13875 ck_krb5_autoget_TGT(realm);
13878 /* Blob from gss-client */
13879 for (trial = 0; trial < n_gss_trials; trial++) {
13880 /* ftp@hostname first, the host@hostname */
13881 /* the V5 GSSAPI binding canonicalizes this for us... */
13882 ckmakmsg(stbuf,FTP_BUFSIZ,
13883 gss_trials[trial].service_name,
13890 "Authenticating to <%s>...\n", stbuf);
13891 send_tok.value = stbuf;
13892 send_tok.length = strlen(stbuf);
13893 maj_stat = gss_import_name(&min_stat, &send_tok,
13894 gss_nt_service_name,
13897 if (maj_stat != GSS_S_COMPLETE) {
13898 user_gss_error(maj_stat, min_stat, "parsing name");
13899 secure_error("name parsed <%s>\n", stbuf);
13902 token_ptr = GSS_C_NO_BUFFER;
13903 gcontext = GSS_C_NO_CONTEXT; /* structure copy */
13907 fprintf(stderr, "calling gss_init_sec_context\n");
13909 gss_init_sec_context(&min_stat,
13910 GSS_C_NO_CREDENTIAL,
13914 gss_trials[trial].mech_type,
13915 GSS_C_MUTUAL_FLAG |
13916 GSS_C_REPLAY_FLAG |
13918 GSS_C_DELEG_FLAG : 0),
13920 /* channel bindings */
13921 (krb5_d_no_addresses ?
13922 GSS_C_NO_CHANNEL_BINDINGS :
13925 NULL, /* ignore mech type */
13927 NULL, /* ignore ret_flags */
13929 ); /* ignore time_rec */
13931 if (maj_stat != GSS_S_COMPLETE &&
13932 maj_stat != GSS_S_CONTINUE_NEEDED) {
13933 if (trial == n_gss_trials-1)
13934 user_gss_error(maj_stat,
13936 "initializing context"
13938 gss_release_name(&min_stat, &target_name);
13939 /* maybe we missed on the service name */
13942 if (send_tok.length != 0) {
13944 reply_parse = "ADAT="; /* for ftpcmd() later */
13947 radix_encode(send_tok.value,
13955 "Base 64 encoding failed: %s\n",
13956 radix_error(kerror)
13958 goto gss_complete_loop;
13960 comcode = ftpcmd("ADAT",out_buf,-1,-1,0);
13961 if (comcode != REPLY_COMPLETE
13962 && comcode != REPLY_CONTINUE /* (335) */
13964 if (trial == n_gss_trials-1) {
13965 fprintf(stderr, "GSSAPI ADAT failed\n");
13966 /* force out of loop */
13967 maj_stat = GSS_S_FAILURE;
13970 Backoff to the v1 gssapi is still possible.
13971 Send a new AUTH command. If that fails,
13972 terminate the loop.
13974 if (ftpcmd("AUTH GSSAPI",NULL,0,0,ftp_vbm)
13975 != REPLY_CONTINUE) {
13977 "GSSAPI ADAT failed, AUTH restart failed\n");
13978 /* force out of loop */
13979 maj_stat = GSS_S_FAILURE;
13983 if (!reply_parse) {
13985 "No authentication data received from server\n");
13986 if (maj_stat == GSS_S_COMPLETE) {
13988 "...but no more was needed\n");
13989 goto gss_complete_loop;
13991 user_gss_error(maj_stat,
13995 goto gss_complete_loop;
13999 kerror = radix_encode(reply_parse,out_buf,i,&len,
14003 "Base 64 decoding failed: %s\n",
14004 radix_error(kerror));
14005 goto gss_complete_loop;
14008 /* everything worked */
14009 token_ptr = &recv_tok;
14010 recv_tok.value = out_buf;
14011 recv_tok.length = len;
14014 /* get out of loop clean */
14016 trial = n_gss_trials-1;
14017 gss_release_buffer(&min_stat, &send_tok);
14018 gss_release_name(&min_stat, &target_name);
14021 } while (maj_stat == GSS_S_CONTINUE_NEEDED);
14024 if (maj_stat == GSS_S_COMPLETE)
14027 if (maj_stat == GSS_S_COMPLETE) {
14028 printf("GSSAPI authentication succeeded\n");
14029 reply_parse = NULL;
14030 auth_type = "GSSAPI";
14033 fprintf(stderr, "GSSAPI authentication failed\n");
14034 reply_parse = NULL;
14038 fprintf(stderr, "GSSAPI rejected as an authentication type\n");
14039 if (ftpcode == 500 || ftpcode == 502)
14043 #endif /* FTP_GSSAPI */
14045 if (ftp_auth_type[j] == FTA_SRP && ck_srp_is_installed()) {
14046 if (srp_ftp_auth(ftp_user_host,NULL,NULL))
14048 else if (ftpcode == 500 || ftpcode == 502)
14051 #endif /* FTP_SRP */
14053 if (ftp_auth_type[j] == FTA_K4 && ck_krb4_is_installed()) {
14054 n = ftpcmd("AUTH KERBEROS_V4",NULL,0,0,ftp_vbm);
14055 if (n == REPLY_CONTINUE) {
14056 char tgt[4*REALM_SZ+1];
14060 printf("KERBEROS_V4 accepted as authentication type\n");
14061 ckstrncpy(inst, (char *) krb_get_phost(ftp_user_host),INST_SZ);
14062 ckstrncpy(ftp_realm,
14063 (char *)ck_krb4_realmofhost(ftp_user_host),
14067 ckmakmsg(tgt,sizeof(tgt),"krbtgt.",ftp_realm,"@",ftp_realm);
14068 rc = ck_krb4_tkt_isvalid(tgt);
14070 if (rc <= 0 && krb4_autoget)
14071 ck_krb4_autoget_TGT(ftp_realm);
14074 kerror = krb_mk_req(&ftp_tkt,service,inst,ftp_realm,checksum);
14075 if (kerror == KDC_PR_UNKNOWN) {
14077 kerror = krb_mk_req(&ftp_tkt,
14085 fprintf(stderr, "Kerberos V4 krb_mk_req failed: %s\n",
14086 krb_get_err_text(kerror));
14088 kerror = krb_get_cred(service, inst, ftp_realm,&ftp_cred);
14090 fprintf(stderr, "Kerberos V4 krb_get_cred failed: %s\n",
14091 krb_get_err_text(kerror));
14095 rc = des_key_sched(ftp_cred.session, ftp_sched);
14097 printf("?Invalid DES key specified in credentials\r\n");
14098 debug(F110,"ftp_auth",
14099 "invalid DES Key specified in credentials",0);
14100 } else if ( rc == -2 ) {
14101 printf("?Weak DES key specified in credentials\r\n");
14102 debug(F110,"ftp_auth",
14103 "weak DES Key specified in credentials",0);
14104 } else if ( rc != 0 ) {
14105 printf("?DES Key Schedule not set by credentials\r\n");
14106 debug(F110,"ftp_auth",
14107 "DES Key Schedule not set by credentials",0);
14109 reply_parse = "ADAT=";
14111 kerror = radix_encode(ftp_tkt.dat, out_buf, ftp_tkt.length,
14114 fprintf(stderr, "Base 64 encoding failed: %s\n",
14115 radix_error(kerror));
14118 if (i > FTP_BUFSIZ - 6)
14119 printf("?ADAT data too long\n");
14120 if (ftpcmd("ADAT",out_buf,-1,-1,0) !=
14122 fprintf(stderr, "Kerberos V4 authentication failed\n");
14125 if (!reply_parse) {
14127 "No authentication data received from server\n");
14130 i = sizeof(out_buf);
14132 radix_encode(reply_parse, out_buf, 0, &i, RADIX_DECODE);
14134 fprintf(stderr, "Base 64 decoding failed: %s\n",
14135 radix_error(kerror));
14138 kerror = krb_rd_safe(out_buf, i,
14143 #endif /* KRB524 */
14149 fprintf(stderr, "Kerberos V4 krb_rd_safe failed: %s\n",
14150 krb_get_err_text(kerror));
14154 /* fetch the (modified) checksum */
14155 memcpy(&cksum, ftp_msg_data.app_data, sizeof(cksum));
14156 if (ntohl(cksum) == checksum + 1) {
14158 printf("Kerberos V4 authentication succeeded\n");
14159 reply_parse = NULL;
14160 auth_type = "KERBEROS_V4";
14164 "Kerberos V4 mutual authentication failed\n");
14166 reply_parse = NULL;
14171 "KERBEROS_V4 rejected as an authentication type\n");
14172 if (ftpcode == 500 || ftpcode == 502)
14176 #endif /* FTP_KRB4 */
14178 if (ftp_auth_type[j] == FTA_TLS && ck_ssleay_is_installed()) {
14181 ftpcmd("HOST",ftp_user_host,0,0,0);
14184 #endif /* FTPHOST */
14185 n = ftpcmd("AUTH TLS",NULL,0,0,ftp_vbm);
14186 if (n != REPLY_COMPLETE)
14187 n = ftpcmd("AUTH TLS-P",NULL,0,0,ftp_vbm);
14188 if (n == REPLY_COMPLETE) {
14190 printf("TLS accepted as authentication type\n");
14194 if (ssl_ftp_active_flag ) {
14199 fprintf(stderr,"TLS authentication failed\n");
14202 socket_close(csocket);
14203 #else /* TCPIPLIB */
14204 #ifdef USE_SHUTDOWN
14205 shutdown(csocket, 1+1);
14206 #endif /* USE_SHUTDOWN */
14208 #endif /* TCPIPLIB */
14210 if (ftp_hookup(ftp_user_host,ftp_port,0) == NULL)
14215 fprintf(stderr,"TLS rejected as an authentication type\n");
14216 if (ftpcode == 500 || ftpcode == 502)
14220 if (ftp_auth_type[j] == FTA_SSL && ck_ssleay_is_installed()) {
14223 ftpcmd("HOST",ftp_user_host,0,0,0);
14226 #endif /* FTPHOST */
14227 n = ftpcmd("AUTH SSL",NULL,0,0,ftp_vbm);
14228 if (n == REPLY_CONTINUE || n == REPLY_COMPLETE) {
14230 printf("SSL accepted as authentication type\n");
14233 if (ssl_ftp_active_flag) {
14239 fprintf(stderr,"SSL authentication failed\n");
14242 socket_close(csocket);
14243 #else /* TCPIPLIB */
14244 #ifdef USE_SHUTDOWN
14245 shutdown(csocket, 1+1);
14246 #endif /* USE_SHUTDOWN */
14248 #endif /* TCPIPLIB */
14250 if (ftp_hookup(ftp_user_host,ftp_port,0) == NULL)
14255 fprintf(stderr, "SSL rejected as an authentication type\n");
14256 if (ftpcode == 500 || ftpcode == 502)
14260 #endif /* CK_SSL */
14261 /* Other auth types go here ... */
14265 #endif /* FTP_SECURITY */
14269 setprotbuf(unsigned int size)
14271 setprotbuf(size) unsigned int size;
14272 #endif /* CK_ANSIC */
14279 while ((ucbuf = (CHAR *)malloc(actualbuf)) == NULL) {
14285 ucbufsiz = actualbuf - FUDGE_FACTOR;
14286 debug(F101,"setprotbuf ucbufsiz","",ucbufsiz);
14287 if (ucbufsiz < 128) {
14288 printf("WARNING: tiny ucbufsiz: %d\n",ucbufsiz);
14289 } else if (ucbufsiz < 0) {
14290 printf("ERROR: ucbuf allocation failure\n");
14293 maxbuf = actualbuf;
14299 setpbsz(unsigned int size)
14301 setpbsz(size) unsigned int size;
14302 #endif /* CK_ANSIC */
14304 if (!setprotbuf(size)) {
14305 perror("?Error while trying to malloc PROT buffer:");
14308 #endif /* FTP_SRP */
14312 reply_parse = "PBSZ=";
14313 ckmakmsg(ftpcmdbuf,FTP_BUFSIZ,"PBSZ ",
14315 ssl_ftp_active_flag ? "0" :
14316 #endif /* CK_SSL */
14317 ckuitoa(actualbuf),NULL,NULL);
14318 if (ftpcmd(ftpcmdbuf,NULL,0,0,0) != REPLY_COMPLETE) {
14320 printf("?Unable to negotiate PROT buffer size with FTP server\n");
14326 if ((maxbuf = (unsigned int) atol(reply_parse)) > actualbuf)
14327 maxbuf = actualbuf;
14329 maxbuf = actualbuf;
14330 ucbufsiz = maxbuf - FUDGE_FACTOR;
14331 debug(F101,"setpbsz ucbufsiz","",ucbufsiz);
14332 reply_parse = NULL;
14337 cancel_remote(din) int din; {
14338 CHAR buf[FTP_BUFSIZ];
14342 #endif /* BSDSELECT */
14344 int fds[2], fdcnt = 0;
14345 #endif /* IBMSELECT */
14352 debug(F100,"ftp cancel_remote entry","",0);
14354 if (ssl_ftp_active_flag) {
14356 * Send Telnet IP, Telnet DM but do so inline and within the
14367 count = SSL_write(ssl_ftp_con, buf, 4);
14368 debug(F111,"ftp cancel_remote","SSL_write(IAC IP IAC DM)",count);
14369 error = SSL_get_error(ssl_ftp_con,count);
14370 debug(F111,"ftp cancel_remote","SSL_get_error()",error);
14372 case SSL_ERROR_NONE:
14374 case SSL_ERROR_WANT_WRITE:
14375 case SSL_ERROR_WANT_READ:
14376 case SSL_ERROR_SYSCALL:
14379 int gle = GetLastError();
14382 case SSL_ERROR_WANT_X509_LOOKUP:
14383 case SSL_ERROR_SSL:
14384 case SSL_ERROR_ZERO_RETURN:
14390 #endif /* CK_SSL */
14393 * send IAC in urgent mode instead of DM because 4.3BSD places oob mark
14394 * after urgent byte rather than before as is protocol now.
14400 if ((x = send(csocket, (SENDARG2TYPE)buf, 3, MSG_OOB)) != 3)
14402 debug(F101,"ftp cancel_remote send 1","",x);
14404 x = send(csocket,(SENDARG2TYPE)buf,1,0);
14405 debug(F101,"ftp cancel_remote send 2","",x);
14407 x = scommand("ABOR");
14408 debug(F101,"ftp cancel_remote scommand","",x);
14411 FD_SET(csocket, &mask);
14413 FD_SET(din, &mask);
14415 nfnd = empty(&mask, 10);
14416 debug(F101,"ftp cancel_remote empty","",nfnd);
14424 #endif /* FTP_PROXY */
14427 debug(F110,"ftp cancel_remote","D",0);
14428 if (din && FD_ISSET(din, &mask)) {
14429 /* Security: No threat associated with this read. */
14430 /* But you can't simply read the TLS data stream */
14432 if (ssl_ftp_data_active_flag) {
14434 while ((count = SSL_read(ssl_ftp_data_con, buf, FTP_BUFSIZ)) > 0)
14437 #endif /* CK_SSL */
14439 while (recv(din, (SENDARG2TYPE)buf, FTP_BUFSIZ,0) > 0)
14443 debug(F110,"ftp cancel_remote","E",0);
14444 #else /* BSDSELECT */
14452 nfnd = empty(fds, fdcnt, 10);
14453 debug(F101,"ftp cancel_remote empty","",nfnd);
14461 #endif /* FTP_PROXY */
14464 debug(F110,"ftp cancel_remote","D",0);
14465 if (din && select(&din, 1,0,0,1) ) {
14467 if (ssl_ftp_data_active_flag) {
14469 while ((count = SSL_read(ssl_ftp_data_con, buf, FTP_BUFSIZ)) > 0)
14472 #endif /* CK_SSL */
14474 while (recv(din, (SENDARG2TYPE)buf, FTP_BUFSIZ,0) > 0)
14478 debug(F110,"ftp cancel_remote","E",0);
14479 #else /* IBMSELECT */
14480 Some form of select is required.
14481 #endif /* IBMSELECT */
14482 #endif /* BSDSELECT */
14483 if (getreply(0,-1,-1,ftp_vbm,0) == REPLY_ERROR && ftpcode == 552) {
14484 debug(F110,"ftp cancel_remote","F",0);
14485 /* 552 needed for NIC style cancel */
14486 getreply(0,-1,-1,ftp_vbm,0);
14487 debug(F110,"ftp cancel_remote","G",0);
14489 debug(F110,"ftp cancel_remote","H",0);
14490 getreply(0,-1,-1,ftp_vbm,0);
14491 debug(F110,"ftp cancel_remote","I",0);
14498 fts_dpl(x) int x; {
14501 || !ck_crypt_is_installed()
14506 printf("?Cannot set protection level to PRIVATE\n");
14509 printf("?Cannot set protection level to SAFE\n");
14517 if (x == FPL_SAF &&
14518 (!strcmp(auth_type,"SSL") || !strcmp(auth_type,"TLS"))) {
14519 printf("Cannot set protection level to safe\n");
14522 #endif /* CK_SSL */
14523 /* Start with a PBSZ of 1 meg */
14524 if (x != FPL_CLR) {
14525 if (setpbsz(DEFAULT_PBSZ) < 0)
14528 y = ftpcmd(x == FPL_CLR ? "PROT C" :
14529 (x == FPL_SAF ? "PROT S" : "PROT P"), NULL, 0, 0,ftp_vbm);
14530 if (y == REPLY_COMPLETE) {
14538 fts_cpl(x) int x; {
14541 || !ck_crypt_is_installed()
14546 printf("?Cannot set protection level to PRIVATE\n");
14549 printf("?Cannot set protection level to SAFE\n");
14555 if (x == FPL_CLR) {
14556 y = ftpcmd("CCC",NULL,0,0,ftp_vbm);
14557 if (y == REPLY_COMPLETE) {
14569 user_gss_error(maj_stat, min_stat, s)
14570 OM_uint32 maj_stat, min_stat;
14573 /* a lot of work just to report the error */
14574 OM_uint32 gmaj_stat, gmin_stat, msg_ctx;
14575 gss_buffer_desc msg;
14578 gmaj_stat = gss_display_status(&gmin_stat, maj_stat,
14584 if ((gmaj_stat == GSS_S_COMPLETE)||
14585 (gmaj_stat == GSS_S_CONTINUE_NEEDED)) {
14586 fprintf(stderr, "GSSAPI error major: %s\n",
14588 gss_release_buffer(&gmin_stat, &msg);
14590 if (gmaj_stat != GSS_S_CONTINUE_NEEDED)
14595 gmaj_stat = gss_display_status(&gmin_stat, min_stat,
14601 if ((gmaj_stat == GSS_S_COMPLETE)||
14602 (gmaj_stat == GSS_S_CONTINUE_NEEDED)) {
14603 fprintf(stderr, "GSSAPI error minor: %s\n", (char*)msg.value);
14604 gss_release_buffer(&gmin_stat, &msg);
14606 if (gmaj_stat != GSS_S_CONTINUE_NEEDED)
14609 fprintf(stderr, "GSSAPI error: %s\n", s);
14611 #endif /* FTP_GSSAPI */
14619 #endif /* HPUX5WINTCP */
14620 #endif /* datageneral */
14621 #endif /* NOMHHOST */
14624 static struct in_addr inaddrx;
14625 #endif /* INADDRX */
14628 ftp_hookup(host, port, tls) char * host; int port; int tls; {
14629 register struct hostent *hp = 0;
14631 #ifdef IPTOS_THROUGHPUT
14633 #endif /* IPTOS_THROUGHPUT */
14634 #endif /* IP_TOS */
14637 static char hostnamebuf[MAXHOSTNAMELEN];
14638 char hostname[MAXHOSTNAMELEN] /* , *p, *q */ ;
14647 debug(F111,"ftp_hookup",host,port);
14650 if (tcp_http_proxy) {
14651 struct servent *destsp;
14654 ckmakmsg(proxyhost,HTTPCPYL,host,":",ckuitoa(port),NULL);
14655 for (p = tcp_http_proxy, q = hostname;
14656 *p != '\0' && *p != ':';
14667 destsp = getservbyname(p,"tcp");
14669 cport = ntohs(destsp->s_port);
14675 #endif /* NOHTTP */
14677 ckstrncpy(hostname,host,MAXHOSTNAMELEN);
14680 memset((char *)&hisctladdr, 0, sizeof (hisctladdr));
14681 hisctladdr.sin_addr.s_addr = inet_addr(host);
14682 if (hisctladdr.sin_addr.s_addr != INADDR_NONE) /* 2010-03-29 */
14684 debug(F110,"ftp hookup A",hostname,0);
14685 hisctladdr.sin_family = AF_INET;
14686 ckstrncpy(hostnamebuf, hostname, MAXHOSTNAMELEN);
14688 debug(F110,"ftp hookup B",hostname,0);
14689 hp = gethostbyname(hostname);
14691 hp = ck_copyhostent(hp); /* make safe copy that won't change */
14692 #endif /* HADDRLIST */
14694 fprintf(stderr, "ftp: %s: Unknown host\n", host);
14699 return((char *) 0);
14701 hisctladdr.sin_family = hp->h_addrtype;
14703 memcpy((char *)&hisctladdr.sin_addr, hp->h_addr_list[0],
14704 sizeof(hisctladdr.sin_addr));
14705 #else /* HADDRLIST */
14706 memcpy((char *)&hisctladdr.sin_addr, hp->h_addr,
14707 sizeof(hisctladdr.sin_addr));
14708 #endif /* HADDRLIST */
14709 ckstrncpy(hostnamebuf, hp->h_name, MAXHOSTNAMELEN);
14711 debug(F110,"ftp hookup C",hostnamebuf,0);
14712 ftp_host = hostnamebuf;
14713 s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
14714 debug(F101,"ftp hookup socket","",s);
14716 perror("ftp: socket");
14723 hisctladdr.sin_port = htons(cport);
14727 printf("hisctladdr=%d\n",sizeof(hisctladdr));
14728 printf("hisctladdr.sin_addr=%d\n",sizeof(hisctladdr.sin_addr));
14729 printf("sockaddr_in=%d\n",sizeof(struct sockaddr_in));
14730 printf("hisctladdr.sin_addr.s_addr=%d\n",sizeof(hisctladdr.sin_addr.s_addr));
14731 #endif /* COMMENT */
14734 debug(F100,"ftp hookup HADDRLIST","",0);
14737 debug(F100,"ftp hookup no HADDRLIST","",0);
14739 #endif /* HADDRLIST */
14740 (connect(s, (struct sockaddr *)&hisctladdr, sizeof (hisctladdr)) < 0) {
14741 debug(F101,"ftp hookup connect failed","",errno);
14743 if (hp && hp->h_addr_list[1]) {
14744 int oerrno = errno;
14746 fprintf(stderr, "ftp: connect to address %s: ",
14747 inet_ntoa(hisctladdr.sin_addr));
14749 perror((char *) 0);
14751 memcpy((char *)&hisctladdr.sin_addr,
14752 hp->h_addr_list[0],
14753 sizeof(hisctladdr.sin_addr));
14754 fprintf(stdout, "Trying %s...\n",
14755 inet_ntoa(hisctladdr.sin_addr));
14758 #else /* TCPIPLIB */
14760 #endif /* TCPIPLIB */
14761 s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
14763 perror("ftp: socket");
14772 #endif /* HADDRLIST */
14773 perror("ftp: connect");
14777 debug(F100,"ftp hookup connect ok","",0);
14779 len = sizeof (myctladdr);
14781 if (getsockname(s, (struct sockaddr *)&myctladdr, &len) < 0) {
14782 debug(F101,"ftp hookup getsockname failed","",errno);
14783 perror("ftp: getsockname");
14787 debug(F100,"ftp hookup getsockname ok","",0);
14790 if (tcp_http_proxy) {
14792 char * agent = "Kermit 95"; /* Default user agent */
14794 char * agent = "C-Kermit";
14797 if (http_connect(s,agent,NULL,
14798 tcp_http_proxy_user,
14799 tcp_http_proxy_pwd,
14806 #else /* TCPIPLIB */
14808 #endif /* TCPIPLIB */
14810 while (foo == NULL && tcp_http_proxy != NULL ) {
14812 if (tcp_http_proxy_errno == 401 ||
14813 tcp_http_proxy_errno == 407 ) {
14814 char uid[UIDBUFLEN];
14816 struct txtbox tb[2];
14820 tb[0].t_len = UIDBUFLEN;
14821 tb[0].t_lbl = "Proxy Userid: ";
14822 tb[0].t_dflt = NULL;
14826 tb[1].t_lbl = "Proxy Passphrase: ";
14827 tb[1].t_dflt = NULL;
14830 ok = uq_mtxt("Proxy Server Authentication Required\n",
14833 if (ok && uid[0]) {
14834 char * proxy_user, * proxy_pwd;
14836 proxy_user = tcp_http_proxy_user;
14837 proxy_pwd = tcp_http_proxy_pwd;
14839 tcp_http_proxy_user = uid;
14840 tcp_http_proxy_pwd = pwd;
14842 foo = ftp_hookup(host, port, 0);
14844 debug(F110,"ftp_hookup()",foo,0);
14845 memset(pwd,0,PWDSIZ);
14846 tcp_http_proxy_user = proxy_user;
14847 tcp_http_proxy_pwd = proxy_pwd;
14855 perror("ftp: connect");
14859 ckstrncpy(hostnamebuf, proxyhost, MAXHOSTNAMELEN);
14861 #endif /* NOHTTP */
14868 * If the connection is over an SSL proxy then the
14869 * auth_type will be NULL. However, I'm not sure
14870 * whether we should protect the data channel in
14871 * that case or not.
14874 debug(F100,"ftp hookup use_tls","",0);
14876 debug(F100,"ftp hookup ssl_auth failed","",0);
14884 #endif /* CK_SSL */
14887 #ifdef IPTOS_LOWDELAY
14888 tos = IPTOS_LOWDELAY;
14889 if (setsockopt(csocket, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
14890 perror("ftp: setsockopt TOS (ignored)");
14894 printf("Connected to %s.\n", host);
14896 /* Read greeting from server */
14897 if (getreply(0,ftp_csl,ftp_csr,ftp_vbm,0) > 2) {
14898 debug(F100,"ftp hookup bad reply","",0);
14900 socket_close(csocket);
14901 #else /* TCPIPLIB */
14903 #endif /* TCPIPLIB */
14907 #ifdef SO_OOBINLINE
14911 if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char *)&on,
14913 perror("ftp: setsockopt");
14914 debug(F101,"ftp hookup setsockopt failed","",errno);
14918 debug(F100,"ftp hookup setsockopt ok","",0);
14921 #endif /* SO_OOBINLINE */
14929 debug(F100,"ftp hookup bad","",0);
14932 #else /* TCPIPLIB */
14934 #endif /* TCPIPLIB */
14946 /* The purpose of the initial REST 0 is not clear, but other FTP */
14947 /* clients do it. In any case, failure of this command is not a */
14948 /* reliable indication that the server does not support Restart. */
14952 n = ftpcmd("REST 0",NULL,0,0,0);
14953 if (n == REPLY_COMPLETE)
14957 printf("WARNING: Unable to restore file pointer.\n");
14958 #endif /* COMMENT */
14960 n = ftpcmd("SYST",NULL,0,0,0); /* Get server system type */
14961 if (n == REPLY_COMPLETE) {
14962 register char *cp, c = NUL;
14963 cp = ckstrchr(ftp_reply_str+4,' '); /* Get first word of reply */
14965 cp = ckstrchr(ftp_reply_str+4,'\r');
14969 c = *cp; /* Save this char */
14970 *cp = '\0'; /* Replace it with NUL */
14973 printf("Remote system type is %s.\n",ftp_reply_str+4);
14974 ckstrncpy(ftp_srvtyp,ftp_reply_str+4,SRVNAMLEN);
14975 if (cp) /* Put back saved char */
14978 alike = !ckstrcmp(ftp_srvtyp,myostype,-1,0);
14980 if (!ckstrcmp(ftp_srvtyp,"UNIX",-1,0)) servertype = SYS_UNIX;
14981 else if (!ckstrcmp(ftp_srvtyp,"WIN32",-1,0)) servertype = SYS_WIN32;
14982 else if (!ckstrcmp(ftp_srvtyp,"OS/2",-1,0)) servertype = SYS_WIN32;
14983 else if (!ckstrcmp(ftp_srvtyp,"VMS",-1,0)) servertype = SYS_VMS;
14984 else if (!ckstrcmp(ftp_srvtyp,"DOS",-1,0)) servertype = SYS_DOS;
14985 else if (!ckstrcmp(ftp_srvtyp,"TOPS20",-1,0)) servertype = SYS_TOPS20;
14986 else if (!ckstrcmp(ftp_srvtyp,"TOPS10",-1,0)) servertype = SYS_TOPS10;
14990 if (servertype == SYS_UNIX && proxy) unix_proxy = 1;
14991 #endif /* FTP_PROXY */
14993 if (ftp_cmdlin && ftp_xfermode == XMODE_M)
14994 ftp_typ = binary; /* Type given on command line */
14995 else /* Otherwise set it automatically */
14996 ftp_typ = alike ? FTT_BIN : FTT_ASC;
14997 changetype(ftp_typ,0); /* Change to this type */
14998 g_ftp_typ = ftp_typ; /* Make it the global type */
15000 printf("Default transfer mode is %s\n",
15001 ftp_typ ? "BINARY" : "TEXT (\"ASCII\")"
15003 for (i = 0; i < 16; i++) /* Init server FEATure table */
15006 n = ftpcmd("MODE S",NULL,0,0,0); /* We always send in Stream mode */
15008 if (n != REPLY_COMPLETE)
15009 printf("WARNING: Server does not accept MODE S(TREAM)\n");
15010 #endif /* COMMENT */
15011 n = ftpcmd("STRU F",NULL,0,0,0); /* STRU File (not Record or Page) */
15013 if (n != REPLY_COMPLETE)
15014 printf("WARNING: Server does not accept STRU F(ILE)\n");
15015 #endif /* COMMENT */
15017 n = ftpcmd("FEAT",NULL,0,0,0); /* Ask server about features */
15018 if (n == REPLY_COMPLETE) {
15019 debug(F101,"ftp_init FEAT","",sfttab[0]);
15020 if (deblog || ftp_deb) {
15022 for (i = 1; i < 16 && i < nfeattab; i++) {
15023 debug(F111,"ftp_init FEAT",feattab[i].kwd,sfttab[i]);
15025 printf(" Server %s %s\n",
15026 sfttab[i] ? "supports" : "does not support",
15030 /* Deal with disabled MLST opts here if necessary */
15031 /* But why would it be? */
15039 ftp_login(host) char * host; { /* (also called from ckuusy.c) */
15040 static char ftppass[PASSBUFSIZ]="";
15041 char tmp[PASSBUFSIZ];
15042 char *user = NULL, *pass = NULL, *acct = NULL;
15044 extern char uidbuf[];
15045 extern char pwbuf[];
15046 extern int pwflg, pwcrypt;
15048 debug(F111,"ftp_login",ftp_logname,ftp_log);
15050 if (!ckstrcmp(ftp_logname,"anonymous",-1,0))
15052 if (!ckstrcmp(ftp_logname,"ftp",-1,0))
15056 if (auth_type && !strcmp(auth_type, "SRP")) {
15061 #endif /* FTP_SRP */
15063 user = "anonymous";
15064 if (ftp_tmp) { /* They gave a password */
15066 } else if (ftp_apw) { /* SET FTP ANONYMOUS-PASSWORD */
15068 } else { /* Supply user@host */
15069 ckmakmsg(tmp,PASSBUFSIZ,whoami(),"@",myhost,NULL);
15072 debug(F110,"ftp anonymous",pass,0);
15074 #ifdef USE_RUSERPASS
15075 if (ruserpass(host, &user, &pass, &acct) < 0) {
15079 #endif /* USE_RUSERPASS */
15081 user = ftp_logname;
15083 } else if (uidbuf[0] && (ftp_tmp || pwbuf[0] && pwflg)) {
15087 } else if (pwbuf[0] && pwflg) {
15088 ckstrncpy(ftppass,pwbuf,PASSBUFSIZ);
15091 ck_encrypt((char *)ftppass);
15097 while (user == NULL) {
15098 char *myname, prompt[PROMPTSIZ];
15103 ckmakxmsg(prompt,PROMPTSIZ," Name (",host,":",myname,"): ",
15104 NULL,NULL,NULL,NULL,NULL,NULL,NULL);
15106 ckmakmsg(prompt,PROMPTSIZ," Name (",host,"): ",NULL);
15109 ok = uq_txt(NULL,prompt,1,NULL,tmp,PASSBUFSIZ,NULL,
15110 DEFAULT_UQ_TIMEOUT);
15111 if (!ok || *tmp == '\0')
15114 user = brstrip(tmp);
15117 n = ftpcmd("USER",user,-1,-1,ftp_vbm);
15118 if (n == REPLY_COMPLETE) {
15119 /* determine if we need to send a dummy password */
15120 if (ftpcmd("PWD",NULL,0,0,0) != REPLY_COMPLETE)
15121 ftpcmd("PASS dummy",NULL,0,0,1);
15122 } else if (n == REPLY_CONTINUE) {
15123 #ifdef CK_ENCRYPTION
15125 #endif /* CK_ENCRYPTION */
15127 if (pass == NULL) {
15130 ok = uq_txt(NULL," Password: ",2,NULL,ftppass,PASSBUFSIZ,NULL,
15131 DEFAULT_UQ_TIMEOUT);
15133 pass = brstrip(ftppass);
15136 #ifdef CK_ENCRYPTION
15137 oldftp_cpl = ftp_cpl;
15139 #endif /* CK_ENCRYPTION */
15140 n = ftpcmd("PASS",pass,-1,-1,1);
15141 if (!anonymous && pass) {
15143 while (*p++) *(p-1) = NUL;
15144 makestr(&ftp_tmp,NULL);
15146 #ifdef CK_ENCRYPTION
15147 /* level may have changed */
15148 if (ftp_cpl == FPL_PRV)
15149 ftp_cpl = oldftp_cpl;
15150 #endif /* CK_ENCRYPTION */
15152 if (n == REPLY_CONTINUE) {
15154 if (acct == NULL) {
15155 static char ftpacct[80];
15158 ok = uq_txt(NULL," Account: ",2,NULL,ftpacct,80,NULL,
15159 DEFAULT_UQ_TIMEOUT);
15161 acct = brstrip(ftpacct);
15163 n = ftpcmd("ACCT",acct,-1,-1,ftp_vbm);
15165 if (n != REPLY_COMPLETE) {
15166 fprintf(stderr, "FTP login failed.\n");
15168 doexit(BAD_EXIT,-1);
15171 if (!aflag && acct != NULL) {
15172 ftpcmd("ACCT",acct,-1,-1,ftp_vbm);
15174 makestr(&ftp_logname,user);
15177 /* Unprefixed file management commands go to server */
15178 if (autolocus && !ftp_cmdlin) {
15184 if (anonymous && !quiet) {
15185 printf(" Logged in as anonymous (%s)\n",pass);
15186 memset(pass, 0, strlen(pass));
15189 if (doftpcwd(ftp_rdir,-1) < 1)
15190 doexit(BAD_EXIT,-1);
15196 #endif /* FTP_PROXY */
15208 FD_SET(csocket, &mask);
15209 if ((nfnd = empty(&mask,0)) < 0) {
15215 getreply(0,-1,-1,ftp_vbm,0);
15218 #else /* BSDSELECT */
15222 if ((nfnd = empty(&csocket,1,0)) < 0) {
15228 getreply(0,-1,-1,ftp_vbm,0);
15231 #endif /* IBMSELECT */
15232 #endif /* BSDSELECT */
15233 rc = (ftpcmd("REIN",NULL,0,0,ftp_vbm) == REPLY_COMPLETE);
15240 ftp_rename(from, to) char * from, * to; {
15241 int lcs = -1, rcs = -1;
15245 if (lcs < 0) lcs = fcharset;
15247 if (rcs < 0) rcs = ftp_csr;
15249 #endif /* NOCSETS */
15250 if (ftpcmd("RNFR",from,lcs,rcs,ftp_vbm) == REPLY_CONTINUE) {
15251 return(ftpcmd("RNTO",to,lcs,rcs,ftp_vbm) == REPLY_COMPLETE);
15253 return(0); /* Failure */
15257 ftp_umask(mask) char * mask; {
15259 rc = (ftpcmd("SITE UMASK",mask,-1,-1,1) == REPLY_COMPLETE);
15264 ftp_user(user,pass,acct) char * user, * pass, * acct; {
15265 int n = 0, aflag = 0;
15268 if (!auth_type && ftp_aut) {
15270 if (ck_srp_is_installed()) {
15271 if (srp_ftp_auth( NULL, user, pass)) {
15272 makestr(&pass,srp_pass);
15275 #endif /* FTP_SRP */
15277 n = ftpcmd("USER",user,-1,-1,ftp_vbm);
15278 if (n == REPLY_COMPLETE)
15279 n = ftpcmd("PASS dummy",NULL,0,0,1);
15280 else if (n == REPLY_CONTINUE) {
15281 #ifdef CK_ENCRYPTION
15283 #endif /* CK_ENCRYPTION */
15284 if (pass == NULL || !pass[0]) {
15288 ok = uq_txt(NULL," Password: ",2,NULL,pwd,PWDSIZ,NULL,
15289 DEFAULT_UQ_TIMEOUT);
15291 pass = brstrip(pwd);
15294 #ifdef CK_ENCRYPTION
15295 if ((oldftp_cpl = ftp_cpl) == PROT_S)
15297 #endif /* CK_ENCRYPTION */
15298 n = ftpcmd("PASS",pass,-1,-1,1);
15299 memset(pass, 0, strlen(pass));
15300 #ifdef CK_ENCRYPTION
15301 /* level may have changed */
15302 if (ftp_cpl == PROT_P)
15303 ftp_cpl = oldftp_cpl;
15304 #endif /* CK_ENCRYPTION */
15306 if (n == REPLY_CONTINUE) {
15307 if (acct == NULL || !acct[0]) {
15311 ok = uq_txt(NULL," Account: ",2,NULL,pwd,PWDSIZ,NULL,
15312 DEFAULT_UQ_TIMEOUT);
15316 n = ftpcmd("ACCT",acct,-1,-1,ftp_vbm);
15319 if (n != REPLY_COMPLETE) {
15320 printf("Login failed.\n");
15323 if (!aflag && acct != NULL && acct[0]) {
15324 n = ftpcmd("ACCT",acct,-1,-1,ftp_vbm);
15326 if (n == REPLY_COMPLETE) {
15327 makestr(&ftp_logname,user);
15339 return(auth_type ? auth_type : "NULL");
15352 return("confidential");
15368 return("confidential");
15375 /* remote_files() */
15377 Returns next remote filename on success;
15378 NULL on error or no more files with global rfrc set to:
15380 -2: Server error response to NLST, e.g. file not found
15384 #define FTPNAMBUFLEN CKMAXPATH+1024
15386 /* Check: ckmaxfiles CKMAXOPEN */
15388 #define MLSDEPTH 128 /* Stack of open temp files */
15389 static int mlsdepth = 0; /* Temp file stack depth */
15390 static FILE * tmpfilptr[MLSDEPTH+1] = { NULL, NULL }; /* Temp file pointers */
15391 static char * tmpfilnam[MLSDEPTH+1] = { NULL, NULL }; /* Temp file names */
15394 mlsreset() { /* Reset MGET temp-file stack */
15396 for (i = 0; i <= mlsdepth; i++) {
15397 if (tmpfilptr[i]) {
15398 fclose(tmpfilptr[i]);
15399 tmpfilptr[i] = NULL;
15400 if (tmpfilnam[i]) {
15402 unlink(tmpfilnam[i]);
15404 free(tmpfilnam[i]);
15413 remote_files(int new_query, CHAR * arg, CHAR * pattern, int proxy_switch)
15414 #else /* CK_ANSIC */
15415 remote_files(new_query, arg, pattern, proxy_switch)
15417 CHAR * arg; /* That we send to the server */
15418 CHAR * pattern; /* That we use locally */
15420 #endif /* CK_ANSIC */
15421 /* remote_files */ {
15422 static CHAR buf[FTPNAMBUFLEN];
15423 CHAR *cp, *whicharg;
15424 char * cdto = NULL;
15426 int i, x, forced = 0;
15427 int lcs = 0, rcs = 0, xlate = 0;
15429 debug(F101,"ftp remote_files new_query","",new_query);
15430 debug(F110,"ftp remote_files arg",arg,0);
15431 debug(F110,"ftp remote_files pattern",pattern,0);
15434 if (pattern) /* Treat empty pattern same as NULL */
15437 if (arg) /* Ditto for arg */
15444 if (tmpfilptr[mlsdepth]) {
15445 fclose(tmpfilptr[mlsdepth]);
15446 tmpfilptr[mlsdepth] = NULL;
15448 if (!ftp_deb && !deblog)
15449 unlink(tmpfilnam[mlsdepth]);
15453 if (tmpfilptr[mlsdepth] == NULL) {
15454 extern char * tempdir;
15456 debug(F110,"ftp remote_files tempdir",tempdir,0);
15462 p = getenv("K95TMP");
15464 p = getenv("K2TMP");
15468 p = getenv("CK_TMP");
15470 p = getenv("TMPDIR");
15471 if (!p) p = getenv("TEMP");
15472 if (!p) p = getenv("TMP");
15475 int len = strlen(p);
15476 if (p[len-1] != '/'
15478 && p[len-1] != '\\'
15481 static char foo[CKMAXPATH];
15482 ckstrncpy(foo,p,CKMAXPATH);
15483 ckstrncat(foo,"/",CKMAXPATH);
15487 #else /* OS2ORUNIX */
15489 #endif /* OS2ORUNIX */
15490 #ifdef UNIX /* Systems that have a standard */
15491 p = "/tmp/"; /* temporary directory... */
15497 #endif /* datageneral */
15500 debug(F110,"ftp remote_files p",p,0);
15502 /* Get temp file */
15504 if ((tmpfilnam[mlsdepth] = (char *)malloc(CKMAXPATH+1))) {
15505 ckmakmsg((char *)tmpfilnam[mlsdepth],
15506 CKMAXPATH+1,p,"ckXXXXXX",NULL,NULL);
15508 printf("?Malloc failure: remote_files()\n");
15514 char * tmpfil = mktemp((char *)tmpfilnam[mlsdepth]);
15516 ckstrncpy(tmpfilnam[mlsdepth],tmpfil,CKMAXPATH+1);
15521 x = mkstemp((char *)tmpfilnam[mlsdepth]);
15522 if (x > -1) close(x); /* We just want the name. */
15524 mktemp((char *)tmpfilnam[mlsdepth]);
15525 #endif /* MKSTEMP */
15526 /* if no mktmpnam() the name will just be "ckXXXXXX"... */
15527 #endif /* MKTEMP */
15530 debug(F111,"ftp remote_files tmpfilnam[mlsdepth]",
15531 tmpfilnam[mlsdepth],mlsdepth);
15534 if (proxy_switch) {
15537 #endif /* FTP_PROXY */
15539 debug(F101,"ftp remote_files ftp_xla","",ftp_xla);
15540 debug(F101,"ftp remote_files ftp_csl","",ftp_csl);
15541 debug(F101,"ftp remote_files ftp_csr","",ftp_csr);
15544 xlate = ftp_xla; /* SET FTP CHARACTER-SET-TRANSLATION */
15545 if (xlate) { /* ON? */
15546 lcs = ftp_csl; /* Local charset */
15547 if (lcs < 0) lcs = fcharset;
15548 if (lcs < 0) xlate = 0;
15550 if (xlate) { /* Still ON? */
15551 rcs = ftp_csx; /* Remote (Server) charset */
15552 if (rcs < 0) rcs = ftp_csr;
15553 if (rcs < 0) xlate = 0;
15555 #endif /* NOCSETS */
15557 forced = mgetforced; /* MGET method forced? */
15558 if (!forced || !mgetmethod) /* Not forced... */
15559 mgetmethod = (sfttab[0] && sfttab[SFT_MLST]) ? /* so pick one */
15563 User's Command: Result:
15564 mget /nlst NLST (NULL)
15565 mget /nlst foo NLST foo
15566 mget /nlst *.txt NLST *.txt
15567 mget /nlst /match:*.txt NLST (NULL)
15568 mget /nlst /match:*.txt foo NLST foo
15569 mget /mlsd MLSD (NULL)
15570 mget /mlsd foo MLSD foo
15571 mget /mlsd *.txt MLSD (NULL)
15572 mget /mlsd /match:*.txt MLSD (NULL)
15573 mget /mlsd /match:*.txt foo MLSD foo
15577 if (pattern) { /* Don't simplify this! */
15579 } else if (mgetmethod == SND_MLS) {
15581 whicharg = iswild((char *)arg) ? NULL : arg;
15587 debug(F110,"ftp remote_files mgetmethod",
15588 mgetmethod == SND_MLS ? "MLSD" : "NLST", 0);
15589 debug(F110,"ftp remote_files whicharg",whicharg,0);
15591 x = recvrequest((mgetmethod == SND_MLS) ? "MLSD" : "NLST",
15592 (char *)tmpfilnam[mlsdepth],
15602 if (x < 0) { /* Chosen method wasn't accepted */
15604 if (ftpcode > 500 && ftpcode < 505 && !quiet)
15605 printf("?%s: Not supported by server\n",
15606 mgetmethod == SND_MLS ? "MLSD" : "NLST"
15608 rfrc = -2; /* Fail */
15611 /* Not forced - if MLSD failed, try NLST */
15612 if (mgetmethod == SND_MLS) { /* Server lied about MLST */
15613 sfttab[SFT_MLST] = 0; /* So disable it */
15614 mlstok = 0; /* and */
15615 mgetmethod = SND_NLS; /* try NLST */
15623 if (proxy_switch) {
15626 #endif /* FTP_PROXY */
15627 tmpfilptr[mlsdepth] = fopen((char *)tmpfilnam[mlsdepth], "r");
15629 if (tmpfilptr[mlsdepth]) {
15630 if (!ftp_deb && !deblog)
15631 unlink(tmpfilnam[mlsdepth]);
15635 if (!tmpfilptr[mlsdepth]) {
15636 debug(F110,"ftp remote_files open fail",tmpfilnam[mlsdepth],0);
15637 if ((!dpyactive || ftp_deb))
15638 printf("?Can't find list of remote files, oops\n");
15643 printf("LISTFILE: %s\n",tmpfilnam[mlsdepth]);
15646 buf[FTPNAMBUFLEN-1] = NUL;
15647 buf[FTPNAMBUFLEN-2] = NUL;
15649 /* We have to redo all this because the first time was only for */
15650 /* for getting the file list, now it's for getting each file */
15652 if (arg && mgetmethod == SND_MLS) { /* MLSD */
15653 if (!pattern && iswild((char *)arg)) {
15654 pattern = arg; /* Wild arg is really a pattern */
15658 arg = NULL; /* and not an arg */
15660 if (new_query) { /* Initial query? */
15661 cdto = (char *)arg; /* (nonwild) arg given? */
15665 if (cdto) /* If so, then CD to it */
15671 if (fgets((char *)buf, FTPNAMBUFLEN, tmpfilptr[mlsdepth]) == NULL) {
15672 fclose(tmpfilptr[mlsdepth]);
15673 tmpfilptr[mlsdepth] = NULL;
15676 if (!ftp_deb && !deblog)
15677 unlink(tmpfilnam[mlsdepth]);
15679 if (ftp_deb && !deblog) {
15680 printf("(Temporary file %s NOT deleted)\n",
15681 (char *)tmpfilnam[mlsdepth]);
15683 if (mlsdepth <= 0) { /* EOF at depth 0 */
15684 rfrc = -3; /* means we're done */
15687 printf("POPPING(%d)...\n",mlsdepth-1);
15688 if (tmpfilnam[mlsdepth]) free(tmpfilnam[mlsdepth]);
15691 zchdir(".."); /* <-- Not portable */
15694 if (buf[FTPNAMBUFLEN-1]) {
15695 printf("?BUFFER OVERFLOW -- FTP NLST or MLSD string longer than %d\n",
15698 debug(F101,"remote_files buffer overrun","",FTPNAMBUFLEN);
15701 /* debug(F110,"ftp remote_files buf 1",buf,0); */
15702 if ((cp = (CHAR *)ckstrchr((char *)buf,'\n')) != NULL)
15704 if ((cp = (CHAR *)ckstrchr((char *)buf,'\r')) != NULL)
15706 debug(F110,"ftp remote_files buf",buf,0);
15710 printf("[%s]\n",(char *)buf);
15712 havesize = (CK_OFF_T)-1; /* Initialize file facts... */
15714 makestr(&havemdtm,NULL);
15717 if (mgetmethod == SND_NLS) { /* NLST... */
15719 if (!ckmatch((char *)pattern,p,(servertype == SYS_UNIX),1))
15722 } else { /* MLSD... */
15723 p = parsefacts((char *)buf);
15724 switch (havetype) {
15725 case FTYP_FILE: /* File: Get it if it matches */
15727 if (!ckmatch((char *)pattern,p,(servertype == SYS_UNIX),1))
15731 case FTYP_CDIR: /* Current directory */
15732 case FTYP_PDIR: /* Parent directory */
15733 goto again; /* Skip */
15734 case FTYP_DIR: /* (Sub)Directory */
15735 if (!recursive) /* If not /RECURSIVE */
15736 goto again; /* Skip */
15737 if (mlsdepth < MLSDEPTH) {
15740 printf("RECURSING [%s](%d)...\n",p,mlsdepth);
15741 if (doftpcwd(p,0) > 0) {
15743 if (!ckstrchr(p,'/')) {
15744 /* zmkdir() needs dirsep */
15745 if ((p2 = (char *)malloc((int)strlen(p) + 2))) {
15746 strcpy(p2,p); /* SAFE */
15747 strcat(p2,"/"); /* SAFE */
15755 #endif /* NOMKDIR */
15758 p = (char *)remote_files(1,arg,pattern,0);
15761 printf("?mkdir failed: [%s] Depth=%d\n",
15770 printf("?CWD failed: [%s] Depth=%d\n",p,mlsdepth);
15775 printf("MAX DIRECTORY STACK DEPTH EXCEEDED: %d\n",
15786 debug(F101,"remote_files havesize","",havesize);
15787 debug(F101,"remote_files havetype","",havetype);
15788 debug(F110,"remote_files havemdtm",havemdtm,0);
15789 debug(F110,"remote_files name",p,0);
15795 /* N O T P O R T A B L E !!! */
15797 #if (SIZEOF_SHORT == 4)
15798 typedef unsigned short ftp_uint32;
15799 typedef short ftp_int32;
15801 #if (SIZEOF_INT == 4)
15802 typedef unsigned int ftp_uint32;
15803 typedef int ftp_int32;
15805 #if (SIZEOF_LONG == 4)
15806 typedef ULONG ftp_uint32;
15807 typedef long ftp_int32;
15812 /* Perhaps use these in general, certainly use them for GSSAPI */
15814 #ifndef looping_write
15815 #define ftp_int32 int
15816 #define ftp_uint32 unsigned int
15818 looping_write(fd, buf, len)
15820 register CONST char *buf;
15824 register int wrlen = len;
15826 cc = send(fd, (SENDARG2TYPE)buf, wrlen, 0);
15828 if (errno == EINTR)
15835 } while (wrlen > 0);
15839 #ifndef looping_read
15841 looping_read(fd, buf, len)
15843 register char *buf;
15849 cc = recv(fd, (char *)buf, len,0);
15851 if (errno == EINTR)
15853 return(cc); /* errno is already set */
15854 } else if (cc == 0) {
15864 #endif /* looping_read */
15870 secure_putbyte(fd, c) int fd; CHAR c; {
15874 if (nout == (maxbuf ? maxbuf : actualbuf) - FUDGE_FACTOR) {
15876 if (!ftpissecure())
15877 ret = send(fd, (SENDARG2TYPE)ucbuf,
15878 (maxbuf ? maxbuf : actualbuf) - FUDGE_FACTOR, 0);
15880 ret = secure_putbuf(fd,
15882 (maxbuf ? maxbuf : actualbuf) - FUDGE_FACTOR
15888 #endif /* COMMENT */
15892 * -1 on error (errno set)
15893 * -2 on security error
15896 secure_flush(fd) int fd; {
15902 if (!ftpissecure()) {
15903 rc = send(fd, (SENDARG2TYPE)ucbuf, nout, 0);
15907 rc = secure_putbuf(fd, ucbuf, nout);
15912 rc = (!ftpissecure()) ? 0 : secure_putbuf(fd, (CHAR *)"", nout = 0);
15915 if (rc > -1 && len > 0 && fdispla != XYFD_B) {
15918 ftscreen(SCR_PT,'D',(CK_OFF_T)spackets,NULL);
15923 #ifdef COMMENT /* (not used) */
15927 * -2 on security error
15931 secure_putc(char c, int fd)
15933 secure_putc(c, fd) char c; int fd;
15934 #endif /* CK_ANSIC */
15935 /* secure_putc */ {
15936 return(secure_putbyte(fd, (CHAR) c));
15938 #endif /* COMMENT */
15942 * -1 on error (errno set)
15943 * -2 on security error
15947 secure_write(int fd, CHAR * buf, unsigned int nbyte)
15949 secure_write(fd, buf, nbyte)
15952 unsigned int nbyte;
15953 #endif /* CK_ANSIC */
15959 if (check_data_connection(fd,1) < 0) {
15963 #endif /* FTP_TIMEOUT */
15965 if (!ftpissecure()) {
15967 if ((ret = send(fd, (SENDARG2TYPE)ucbuf, nout, 0)) < 0)
15971 return(send(fd,(SENDARG2TYPE)buf,nbyte,0));
15973 int ucbuflen = (maxbuf ? maxbuf : actualbuf) - FUDGE_FACTOR;
15976 while (bsent < nbyte) {
15977 int b2cp = ((nbyte - bsent) > (ucbuflen - nout) ?
15978 (ucbuflen - nout) : (nbyte - bsent));
15981 debug(F101,"secure_write ucbuflen","",ucbuflen);
15982 debug(F101,"secure_write ucbufsiz","",ucbufsiz);
15983 debug(F101,"secure_write bsent","",bsent);
15984 debug(F101,"secure_write b2cp","",b2cp);
15987 memcpy(&ucbuf[nout],&buf[bsent],b2cp);
15991 if (nout == ucbuflen) {
15993 ret = secure_putbuf(fd, ucbuf, ucbuflen);
16004 * -1 on error (errno set)
16005 * -2 on security error
16009 secure_putbuf(int fd, CHAR * buf, unsigned int nbyte)
16011 secure_putbuf(fd, buf, nbyte) int fd; CHAR * buf; unsigned int nbyte;
16012 #endif /* CK_ANSIC */
16014 static char *outbuf = NULL; /* output ciphertext */
16015 #ifdef FTP_SECURITY
16016 static unsigned int bufsize = 0; /* size of outbuf */
16017 #endif /* FTP_SECURITY */
16018 ftp_int32 length = 0;
16019 ftp_uint32 net_len = 0;
16021 /* Other auth types go here ... */
16023 if (ssl_ftp_data_active_flag) {
16026 /* there is no need to send an empty buffer when using SSL/TLS */
16030 count = SSL_write(ssl_ftp_data_con, buf, nbyte);
16031 error = SSL_get_error(ssl_ftp_data_con,count);
16033 case SSL_ERROR_NONE:
16035 case SSL_ERROR_WANT_WRITE:
16036 case SSL_ERROR_WANT_READ:
16037 case SSL_ERROR_SYSCALL:
16040 int gle = GetLastError();
16043 debug(F111,"secure_putbuf","SSL_ERROR_SYSCALL",gle);
16046 case SSL_ERROR_WANT_X509_LOOKUP:
16047 case SSL_ERROR_SSL:
16048 case SSL_ERROR_ZERO_RETURN:
16050 SSL_shutdown(ssl_ftp_data_con);
16051 SSL_free(ssl_ftp_data_con);
16052 ssl_ftp_data_active_flag = 0;
16053 ssl_ftp_data_con = NULL;
16055 socket_close(data);
16056 #else /* TCPIPLIB */
16057 #ifdef USE_SHUTDOWN
16058 shutdown(data, 1+1);
16059 #endif /* USE_SHUTDOWN */
16061 #endif /* TCPIPLIB */
16068 #endif /* CK_SSL */
16071 if (ck_srp_is_installed() && (strcmp(auth_type, "SRP") == 0)) {
16072 if (bufsize < nbyte + FUDGE_FACTOR) {
16074 (outbuf = realloc(outbuf, (unsigned) (nbyte + FUDGE_FACTOR))):
16075 (outbuf = malloc((unsigned) (nbyte + FUDGE_FACTOR)))) {
16076 bufsize = nbyte + FUDGE_FACTOR;
16079 secure_error("%s (in malloc of PROT buffer)", ck_errstr());
16084 srp_encode(ftp_dpl == FPL_PRV,
16090 secure_error ("srp_encode failed");
16094 #endif /* FTP_SRP */
16096 if (ck_krb4_is_installed() && (strcmp(auth_type, "KERBEROS_V4") == 0)) {
16097 struct sockaddr_in myaddr, hisaddr;
16099 len = sizeof(myaddr);
16100 if (getsockname(fd, (struct sockaddr*)&myaddr, &len) < 0) {
16101 secure_error("secure_putbuf: getsockname failed");
16104 len = sizeof(hisaddr);
16105 if (getpeername(fd, (struct sockaddr*)&hisaddr, &len) < 0) {
16106 secure_error("secure_putbuf: getpeername failed");
16109 if (bufsize < nbyte + FUDGE_FACTOR) {
16111 (outbuf = realloc(outbuf, (unsigned) (nbyte + FUDGE_FACTOR))):
16112 (outbuf = malloc((unsigned) (nbyte + FUDGE_FACTOR)))) {
16113 bufsize = nbyte + FUDGE_FACTOR;
16116 secure_error("%s (in malloc of PROT buffer)", ck_errstr());
16120 if (ftp_dpl == FPL_PRV) {
16121 length = krb_mk_priv(buf, (CHAR *) outbuf, nbyte,
16127 #endif /* KRB524 */
16132 length = krb_mk_safe(buf, (CHAR *) outbuf, nbyte,
16137 #endif /* KRB524 */
16142 if (length == -1) {
16143 secure_error("krb_mk_%s failed for KERBEROS_V4",
16144 ftp_dpl == FPL_PRV ? "priv" : "safe");
16148 #endif /* FTP_KRB4 */
16150 if (ck_gssapi_is_installed() && (strcmp(auth_type, "GSSAPI") == 0)) {
16151 gss_buffer_desc in_buf, out_buf;
16152 OM_uint32 maj_stat, min_stat;
16155 in_buf.value = buf;
16156 in_buf.length = nbyte;
16157 maj_stat = gss_seal(&min_stat, gcontext,
16158 (ftp_dpl == FPL_PRV), /* confidential */
16164 if (maj_stat != GSS_S_COMPLETE) {
16165 /* generally need to deal */
16166 /* ie. should loop, but for now just fail */
16167 user_gss_error(maj_stat, min_stat,
16168 ftp_dpl == FPL_PRV?
16169 "GSSAPI seal failed":
16170 "GSSAPI sign failed");
16173 if (bufsize < out_buf.length) {
16175 (outbuf = realloc(outbuf, (unsigned) out_buf.length)):
16176 (outbuf = malloc((unsigned) out_buf.length))) {
16177 bufsize = out_buf.length;
16180 secure_error("%s (in malloc of PROT buffer)",
16185 memcpy(outbuf, out_buf.value, length=out_buf.length);
16186 gss_release_buffer(&min_stat, &out_buf);
16188 #endif /* FTP_GSSAPI */
16189 net_len = htonl((ULONG) length);
16190 if (looping_write(fd, (char *)&net_len, 4) == -1)
16192 if (looping_write(fd, outbuf, length) != length)
16198 /* fc = 0 means to get a byte; nonzero means to initialize buffer pointers */
16201 secure_getbyte(fd,fc) int fd,fc; {
16202 /* number of chars in ucbuf, pointer into ucbuf */
16203 static unsigned int nin = 0, bufp = 0;
16217 if (check_data_connection(fd,0) < 0)
16219 #endif /* FTP_TIMEOUT */
16222 if (ssl_ftp_data_active_flag) {
16224 count = SSL_read(ssl_ftp_data_con, ucbuf, ucbufsiz);
16225 error = SSL_get_error(ssl_ftp_data_con,count);
16227 if (error != SSL_ERROR_NONE)
16228 debug(F101,"ftp secure_getbyte error","",error);
16230 debug(F101,"ftp secure_getbyte count","",count);
16233 case SSL_ERROR_NONE:
16235 nin = bufp = count;
16238 if (fdispla != XYFD_B) {
16240 ftscreen(SCR_PT,'D',(CK_OFF_T)rpackets,NULL);
16244 case SSL_ERROR_WANT_WRITE:
16245 case SSL_ERROR_WANT_READ:
16246 case SSL_ERROR_SYSCALL:
16249 int gle = GetLastError();
16252 case SSL_ERROR_WANT_X509_LOOKUP:
16253 case SSL_ERROR_SSL:
16254 case SSL_ERROR_ZERO_RETURN:
16256 nin = bufp = count = 0;
16257 SSL_shutdown(ssl_ftp_data_con);
16258 SSL_free(ssl_ftp_data_con);
16259 ssl_ftp_data_active_flag = 0;
16260 ssl_ftp_data_con = NULL;
16262 socket_close(data);
16263 #else /* TCPIPLIB */
16264 #ifdef USE_SHUTDOWN
16265 shutdown(data, 1+1);
16266 #endif /* USE_SHUTDOWN */
16268 #endif /* TCPIPLIB */
16274 #endif /* CK_SSL */
16276 kerror = looping_read(fd, (char *)&length, sizeof(length));
16277 if (kerror != sizeof(length)) {
16278 secure_error("Couldn't read PROT buffer length: %d/%s",
16280 kerror == -1 ? ck_errstr()
16285 debug(F101,"secure_getbyte length","",length);
16286 debug(F101,"secure_getbyte ntohl(length)","",ntohl(length));
16288 length = (ULONG) ntohl(length);
16289 if (length > maxbuf) {
16290 secure_error("Length (%d) of PROT buffer > PBSZ=%u",
16296 if ((kerror = looping_read(fd, ucbuf, length)) != length) {
16297 secure_error("Couldn't read %u byte PROT buffer: %s",
16299 kerror == -1 ? ck_errstr() : "premature EOF"
16304 /* Other auth types go here ... */
16306 if (strcmp(auth_type, "SRP") == 0) {
16307 if ((nin = bufp = srp_decode (ftp_dpl == FPL_PRV,
16313 secure_error ("srp_encode failed" );
16317 #endif /* FTP_SRP */
16319 if (strcmp(auth_type, "KERBEROS_V4") == 0) {
16320 struct sockaddr_in myaddr, hisaddr;
16322 len = sizeof(myaddr);
16323 if (getsockname(fd, (struct sockaddr*)&myaddr, &len) < 0) {
16324 secure_error("secure_putbuf: getsockname failed");
16327 len = sizeof(hisaddr);
16328 if (getpeername(fd, (struct sockaddr*)&hisaddr, &len) < 0) {
16329 secure_error("secure_putbuf: getpeername failed");
16333 kerror = krb_rd_priv(ucbuf, length, ftp_sched,
16338 #endif /* KRB524 */
16339 &hisaddr, &myaddr, &ftp_msg_data);
16341 kerror = krb_rd_safe(ucbuf, length,
16346 #endif /* KRB524 */
16347 &hisaddr, &myaddr, &ftp_msg_data);
16350 secure_error("krb_rd_%s failed for KERBEROS_V4 (%s)",
16351 ftp_dpl == FPL_PRV ? "priv" : "safe",
16352 krb_get_err_text(kerror));
16355 memcpy(ucbuf,ftp_msg_data.app_data,ftp_msg_data.app_length);
16356 nin = bufp = ftp_msg_data.app_length;
16358 #endif /* FTP_KRB4 */
16360 if (strcmp(auth_type, "GSSAPI") == 0) {
16361 gss_buffer_desc xmit_buf, msg_buf;
16362 OM_uint32 maj_stat, min_stat;
16365 xmit_buf.value = ucbuf;
16366 xmit_buf.length = length;
16367 conf_state = (ftp_dpl == FPL_PRV);
16368 /* decrypt/verify the message */
16369 maj_stat = gss_unseal(&min_stat, gcontext, &xmit_buf,
16370 &msg_buf, &conf_state, NULL);
16371 if (maj_stat != GSS_S_COMPLETE) {
16372 user_gss_error(maj_stat, min_stat,
16373 (ftp_dpl == FPL_PRV)?
16374 "failed unsealing ENC message":
16375 "failed unsealing MIC message");
16378 memcpy(ucbuf, msg_buf.value, nin = bufp = msg_buf.length);
16379 gss_release_buffer(&min_stat, &msg_buf);
16381 #endif /* FTP_GSSAPI */
16382 /* Other auth types go here ... */
16384 /* Update file transfer display */
16387 if (fdispla != XYFD_B) {
16389 ftscreen(SCR_PT,'D',(CK_OFF_T)rpackets,NULL);
16396 return(ucbuf[bufp - nin--]);
16399 /* secure_getc(fd,fc)
16401 * fd = file descriptor for connection.
16402 * fc = 0 to get a character, fc != 0 to initialize buffer pointers.
16404 * c>=0 on success (character value)
16406 * -2 on security error
16407 * -3 on timeout (if built with FTP_TIMEOUT defined)
16410 secure_getc(fd,fc) int fd,fc; { /* file descriptor, function code */
16412 if (!ftpissecure()) {
16413 static unsigned int nin = 0, bufp = 0;
16424 if (check_data_connection(fd,0) < 0) {
16425 debug(F100,"secure_getc TIMEOUT","",0);
16430 #endif /* FTP_TIMEOUT */
16432 nin = bufp = recv(fd,(char *)ucbuf,actualbuf,0);
16433 if ((nin == 0) || (nin == (unsigned int)-1)) {
16434 debug(F111,"secure_getc recv errno",ckitoa(nin),errno);
16435 debug(F101,"secure_getc returns EOF","",EOF);
16439 debug(F101,"ftp secure_getc recv","",nin);
16440 ckhexdump("ftp secure_getc recv",ucbuf,16);
16443 if (fdispla != XYFD_B) {
16445 ftscreen(SCR_PT,'D',(CK_OFF_T)rpackets,NULL);
16448 return(ucbuf[bufp - nin--]);
16450 return(secure_getbyte(fd,fc));
16454 * n>0 on success (n == # of bytes read)
16456 * -1 on error (errno set), only for FPL_CLR
16457 * -2 on security error
16460 secure_read(fd, buf, nbyte) int fd; char *buf; int nbyte; {
16464 debug(F101,"secure_read bytes requested","",nbyte);
16467 for (i = 0; nbyte > 0; nbyte--) {
16468 c = secure_getc(fd,0);
16470 case -9: /* Canceled from keyboard */
16471 debug(F101,"ftp secure_read interrupted","",c);
16474 debug(F101,"ftp secure_read error","",c);
16477 debug(F101,"ftp secure_read EOF","",c);
16483 debug(F101,"ftp secure_read timeout","",c);
16485 #endif /* FTP_TIMEOUT */
16493 #ifdef USE_RUSERPASS
16496 * Copyright (c) 1985 Regents of the University of California.
16497 * All rights reserved.
16499 * Redistribution and use in source and binary forms, with or without
16500 * modification, are permitted provided that the following conditions
16502 * 1. Redistributions of source code must retain the above copyright
16503 * notice, this list of conditions and the following disclaimer.
16504 * 2. Redistributions in binary form must reproduce the above copyright
16505 * notice, this list of conditions and the following disclaimer in the
16506 * documentation and/or other materials provided with the distribution.
16507 * 3. All advertising materials mentioning features or use of this software
16508 * must display the following acknowledgement:
16509 * This product includes software developed by the University of
16510 * California, Berkeley and its contributors.
16511 * 4. Neither the name of the University nor the names of its contributors
16512 * may be used to endorse or promote products derived from this software
16513 * without specific prior written permission.
16515 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
16516 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16517 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16518 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
16519 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
16520 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
16521 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
16522 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
16523 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
16524 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
16529 static char sccsid[] = "@(#)ruserpass.c 5.3 (Berkeley) 3/1/91";
16530 #endif /* not lint */
16532 #ifndef MAXHOSTNAMELEN
16533 #define MAXHOSTNAMELEN 64
16537 static FILE * cfile;
16547 static char tokval[100];
16549 static struct toktab {
16553 "default", DEFAULT,
16555 "password", PASSWD,
16557 "account", ACCOUNT,
16571 while ((c = getc(cfile)) != EOF &&
16572 (c == '\n' || c == '\t' || c == ' ' || c == ','))
16578 while ((c = getc(cfile)) != EOF && c != '"') {
16585 while ((c = getc(cfile)) != EOF
16586 && c != '\n' && c != '\t' && c != ' ' && c != ',') {
16593 if (tokval[0] == 0)
16595 for (t = toktab; t->tokstr; t++)
16596 if (!strcmp(t->tokstr, tokval))
16601 ruserpass(host, aname, apass, aacct)
16602 char *host, **aname, **apass, **aacct;
16604 char *hdir, buf[FTP_BUFSIZ], *tmp;
16605 char myname[MAXHOSTNAMELEN], *mydomain;
16606 int t, i, c, usedefault = 0;
16613 hdir = getenv("HOME");
16616 ckmakmsg(buf,FTP_BUFSIZ,hdir,"/.netrc",NULL,NULL);
16617 cfile = fopen(buf, "r");
16618 if (cfile == NULL) {
16619 if (errno != ENOENT)
16623 if (gethostname(myname, MAXHOSTNAMELEN) < 0)
16625 if ((mydomain = ckstrchr(myname, '.')) == NULL)
16629 while ((t = token())) switch(t) {
16640 * Allow match either for user's input host name
16641 * or official hostname. Also allow match of
16642 * incompletely-specified host in local domain.
16644 if (ckstrcmp(host, tokval,-1,1) == 0)
16646 if (ckstrcmp(ftp_host, tokval,-1,0) == 0)
16648 if ((tmp = ckstrchr(ftp_host, '.')) != NULL &&
16649 ckstrcmp(tmp, mydomain,-1,1) == 0 &&
16650 ckstrcmp(ftp_host, tokval, tmp-ftp_host,0) == 0 &&
16651 tokval[tmp - ftp_host] == '\0')
16653 if ((tmp = ckstrchr(host, '.')) != NULL &&
16654 ckstrcmp(tmp, mydomain,-1,1) == 0 &&
16655 ckstrcmp(host, tokval, tmp - host, 0) == 0 &&
16656 tokval[tmp - host] == '\0')
16662 while ((t = token()) && t != MACH && t != DEFAULT) switch(t) {
16667 *aname = malloc((unsigned) strlen(tokval) + 1);
16668 strcpy(*aname, tokval); /* safe */
16670 if (strcmp(*aname, tokval))
16675 if (strcmp(*aname, "anonymous") &&
16676 fstat(fileno(cfile), &stb) >= 0 &&
16677 (stb.st_mode & 077) != 0) {
16678 fprintf(stderr, "Error - .netrc file not correct mode.\n");
16679 fprintf(stderr, "Remove password or correct mode.\n");
16682 if (token() && *apass == 0) {
16683 *apass = malloc((unsigned) strlen(tokval) + 1);
16684 strcpy(*apass, tokval); /* safe */
16688 if (fstat(fileno(cfile), &stb) >= 0
16689 && (stb.st_mode & 077) != 0) {
16690 fprintf(stderr, "Error - .netrc file not correct mode.\n");
16691 fprintf(stderr, "Remove account or correct mode.\n");
16694 if (token() && *aacct == 0) {
16695 *aacct = malloc((unsigned) strlen(tokval) + 1);
16696 strcpy(*aacct, tokval); /* safe */
16701 fprintf(stderr, "Unknown .netrc keyword %s\n", tokval);
16715 #endif /* USE_RUSERPASS */
16717 static char *radixN =
16718 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
16720 static char pad = '=';
16723 radix_encode(inbuf, outbuf, inlen, outlen, decode)
16724 CHAR inbuf[], outbuf[];
16725 int inlen, *outlen, decode;
16732 for (i = 0, j = 0; inbuf[i] && inbuf[i] != pad; i++) {
16733 if ((p = ckstrchr(radixN, inbuf[i])) == NULL)
16741 outbuf[j++] |= D>>4;
16742 outbuf[j] = (D&15)<<4;
16745 outbuf[j++] |= D>>2;
16746 outbuf[j] = (D&3)<<6;
16756 case 2: if (D&15) return(3);
16757 if (strcmp((char *)&inbuf[i], "==")) return(2);
16759 case 3: if (D&3) return(3);
16760 if (strcmp((char *)&inbuf[i], "=")) return(2);
16764 for (i = 0, j = 0; i < inlen; i++) {
16767 outbuf[j++] = radixN[inbuf[i]>>2];
16768 c = (inbuf[i]&3)<<4;
16771 outbuf[j++] = radixN[c|inbuf[i]>>4];
16772 c = (inbuf[i]&15)<<2;
16775 outbuf[j++] = radixN[c|inbuf[i]>>6];
16776 outbuf[j++] = radixN[inbuf[i]&63];
16782 if (i%3) outbuf[j++] = radixN[c];
16784 case 1: outbuf[j++] = pad;
16785 case 2: outbuf[j++] = pad;
16787 outbuf[*outlen = j] = '\0';
16793 radix_error(e) int e;
16796 case 0: return("Success");
16797 case 1: return("Bad character in encoding");
16798 case 2: return("Encoding not properly padded");
16799 case 3: return("Decoded # of bits not a multiple of 8");
16800 case 4: return("Output buffer too small");
16801 default: return("Unknown error");
16804 /* END_RUSERPASS */
16807 /*---------------------------------------------------------------------------+
16809 | Package: srpftp |
16810 | Author: Eugene Jhong |
16812 +---------------------------------------------------------------------------*/
16815 * Copyright (c) 1997-1999 The Stanford SRP Authentication Project
16816 * All Rights Reserved.
16818 * Permission is hereby granted, free of charge, to any person obtaining
16819 * a copy of this software and associated documentation files (the
16820 * "Software"), to deal in the Software without restriction, including
16821 * without limitation the rights to use, copy, modify, merge, publish,
16822 * distribute, sublicense, and/or sell copies of the Software, and to
16823 * permit persons to whom the Software is furnished to do so, subject to
16824 * the following conditions:
16826 * The above copyright notice and this permission notice shall be
16827 * included in all copies or substantial portions of the Software.
16829 * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
16830 * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
16831 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
16833 * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
16834 * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
16835 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
16836 * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
16837 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16839 * In addition, the following conditions apply:
16841 * 1. Any software that incorporates the SRP authentication technology
16842 * must display the following acknowlegment:
16843 * "This product uses the 'Secure Remote Password' cryptographic
16844 * authentication system developed by Tom Wu (tjw@CS.Stanford.EDU)."
16846 * 2. Any software that incorporates all or part of the SRP distribution
16847 * itself must also display the following acknowledgment:
16848 * "This product includes software developed by Tom Wu and Eugene
16849 * Jhong for the SRP Distribution (http://srp.stanford.edu/srp/)."
16851 * 3. Redistributions in source or binary form must retain an intact copy
16852 * of this copyright notice and list of conditions.
16855 #define SRP_PROT_VERSION 1
16857 #ifdef CK_ENCRYPTION
16858 #define SRP_DEFAULT_CIPHER CIPHER_ID_CAST5_CBC
16860 #define SRP_DEFAULT_CIPHER CIPHER_ID_NONE
16861 #endif /* CK_ENCRYPTION */
16863 #define SRP_DEFAULT_HASH HASH_ID_SHA
16865 CHAR srp_pref_cipher = CIPHER_ID_DES3_ECB;
16866 CHAR srp_pref_hash = HASH_ID_SHA;
16868 static struct t_client *tc = NULL;
16869 static CHAR *skey = NULL;
16870 static krypto_context *incrypt = NULL;
16871 static krypto_context *outcrypt = NULL;
16873 typedef unsigned int srp_uint32;
16875 /*--------------------------------------------------------------+
16876 | srp_selcipher: select cipher |
16877 +--------------------------------------------------------------*/
16879 srp_selcipher (cname) char *cname; {
16882 if (!(cd = cipher_getdescbyname (cname))) {
16884 CHAR *list = cipher_getlist ();
16886 fprintf (stderr, "ftp: supported ciphers:\n\n");
16887 for (i = 0; i < strlen (list); i++)
16888 fprintf (stderr, " %s\n", (cipher_getdescbyid(list[i]))->name);
16889 fprintf (stderr, "\n");
16892 srp_pref_cipher = cd->id;
16896 /*--------------------------------------------------------------+
16897 | srp_selhash: select hash |
16898 +--------------------------------------------------------------*/
16900 srp_selhash (hname) char *hname; {
16903 if (!(hd = hash_getdescbyname (hname))) {
16905 CHAR *list = hash_getlist ();
16907 fprintf (stderr, "ftp: supported hash functions:\n\n");
16908 for (i = 0; i < strlen (list); i++)
16909 fprintf (stderr, " %s\n", (hash_getdescbyid(list[i]))->name);
16910 fprintf (stderr, "\n");
16913 srp_pref_hash = hd->id;
16917 /*--------------------------------------------------------------+
16918 | srp_userpass: get username and password |
16919 +--------------------------------------------------------------*/
16921 srp_userpass (host) char *host; {
16922 char tmp[BUFSIZ], prompt[PROMPTSIZ];
16926 #ifdef USE_RUSERPASS
16927 ruserpass (host, &user, &srp_pass, &srp_acct);
16928 #endif /* USE_RUSERPASS */
16930 while (user == NULL) {
16935 if (!myname) myname = "";
16937 ckmakxmsg(prompt,PROMPTSIZ," Name (",host,":",myname,"): ",
16938 NULL,NULL,NULL,NULL,NULL,NULL,NULL);
16940 ckmakmsg(prompt,PROMPTSIZ," Name (",host,"): ",NULL);
16942 ok = uq_txt(NULL,prompt,1,NULL,tmp,BUFSIZ,NULL,
16943 DEFAULT_UQ_TIMEOUT);
16944 if (!ok || *tmp == '\0')
16947 user = brstrip(tmp);
16949 ckstrncpy (srp_user, user,BUFSIZ);
16953 /*--------------------------------------------------------------+
16954 | srp_reset: reset srp information |
16955 +--------------------------------------------------------------*/
16958 if (tc) { t_clientclose (tc); tc = NULL; }
16959 if (incrypt) { krypto_delete (incrypt); incrypt = NULL; }
16960 if (outcrypt) { krypto_delete (outcrypt); outcrypt = NULL; }
16964 /*--------------------------------------------------------------+
16965 | srp_ftp_auth: perform srp authentication |
16966 +--------------------------------------------------------------*/
16968 srp_ftp_auth(host, user, pass)
16978 CHAR buf[FTP_BUFSIZ];
16979 CHAR tmp[FTP_BUFSIZ];
16981 int n, e, clen, blen, len, i;
16985 srp_pass = srp_acct = 0;
16987 n = ftpcmd("AUTH SRP",NULL,0,0,ftp_vbm);
16988 if (n != REPLY_CONTINUE) {
16990 fprintf(stderr, "SRP rejected as an authentication type\n");
16992 } else { /* Send protocol version */
16994 memset (vers, 0, 4);
16995 vers[3] = SRP_PROT_VERSION;
16997 printf ("SRP accepted as authentication type.\n");
16998 bp = tmp; blen = 0;
16999 srp_put (vers, &bp, 4, &blen);
17001 if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE))
17003 reply_parse = "ADAT=";
17004 n = ftpcmd("ADAT",buf,-1,-1,0);
17006 if (n == REPLY_CONTINUE) { /* Get protocol version */
17011 if (e = radix_encode(reply_parse, bp, 0, &blen, RADIX_DECODE))
17013 if (srp_get (&bp, &cp, &blen, &clen) != 4)
17016 if (host) { /* Get username/password if needed */
17017 srp_userpass (host);
17019 ckstrncpy (srp_user, user, BUFSIZ);
17022 bp = tmp; blen = 0; /* Send username */
17023 srp_put (srp_user, &bp, strlen (srp_user), &blen);
17025 if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE))
17027 reply_parse = "ADAT=";
17028 n = ftpcmd("ADAT",buf,-1,-1,0);
17030 if (n == REPLY_CONTINUE) { /* Get N, g and s */
17035 if (e = radix_encode (reply_parse, bp, 0, &blen, RADIX_DECODE))
17037 if (srp_get (&bp, &(N.data), &blen, &(N.len)) < 0)
17039 if (srp_get (&bp, &(g.data), &blen, &(g.len)) < 0)
17041 if (srp_get (&bp, &(s.data), &blen, &(s.len)) < 0)
17043 if ((tc = t_clientopen (srp_user, &N, &g, &s)) == NULL) {
17044 fprintf (stderr, "Unable to open SRP client structure.\n");
17047 wp = t_clientgenexp (tc); /* Send wp */
17048 bp = tmp; blen = 0;
17049 srp_put (wp->data, &bp, wp->len, &blen);
17051 if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE))
17053 reply_parse = "ADAT=";
17054 n = ftpcmd("ADAT",buf,-1,-1,0);
17056 if (n == REPLY_CONTINUE) { /* Get yp */
17061 if (e = radix_encode (reply_parse, bp, 0, &blen, RADIX_DECODE))
17063 if (srp_get (&bp, &(yp.data), &blen, &(yp.len)) < 0)
17066 static char ftppass[PASSBUFSIZ];
17069 ok = uq_txt(NULL," SRP Password: ",2,NULL,ftppass,PASSBUFSIZ,NULL,
17070 DEFAULT_UQ_TIMEOUT);
17072 srp_pass = brstrip(ftppass);
17074 t_clientpasswd (tc, srp_pass);
17075 memset (srp_pass, 0, strlen (srp_pass));
17076 skey = t_clientgetkey (tc, &yp); /* Send response */
17077 bp = tmp; blen = 0;
17078 srp_put (t_clientresponse (tc), &bp, 20, &blen);
17080 if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE))
17082 reply_parse = "ADAT=";
17083 n = ftpcmd("ADAT",buf,-1,-1,0);
17085 if (n == REPLY_CONTINUE) { /* Get response */
17090 if (e = radix_encode (reply_parse, bp, 0, &blen, RADIX_DECODE))
17092 if (srp_get (&bp, &cp, &blen, &clen) != 20)
17094 if (t_clientverify (tc, cp)) {
17095 fprintf (stderr, "WARNING: bad response to client challenge.\n");
17098 bp = tmp; blen = 0; /* Send nothing */
17099 srp_put ("\0", &bp, 1, &blen);
17101 if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE))
17103 reply_parse = "ADAT=";
17104 n = ftpcmd("ADAT",buf,-1,-1,0);
17106 if (n == REPLY_CONTINUE) { /* Get cipher & hash lists, seqnum */
17111 int clist_len, hlist_len;
17116 if (e = radix_encode (reply_parse, bp, 0, &blen, RADIX_DECODE))
17118 if (srp_get (&bp, &clist, &blen, &clist_len) < 0)
17120 if (srp_get (&bp, &hlist, &blen, &hlist_len) < 0)
17122 if (srp_get (&bp, &cp, &blen, &clen) != 4)
17124 memcpy (seqnum, cp, 4);
17125 if (cipher_supported (clist, srp_pref_cipher)) /* Choose cipher */
17126 cid = srp_pref_cipher;
17127 if (!cid && cipher_supported (clist, SRP_DEFAULT_CIPHER))
17128 cid = SRP_DEFAULT_CIPHER;
17130 CHAR *loclist = cipher_getlist ();
17131 for (i = 0; i < strlen (loclist); i++)
17132 if (cipher_supported (clist, loclist[i])) {
17138 fprintf (stderr, "Unable to agree on cipher.\n");
17143 if (srp_pref_hash && hash_supported (hlist, srp_pref_hash))
17144 hid = srp_pref_hash;
17146 if (!hid && hash_supported (hlist, SRP_DEFAULT_HASH))
17147 hid = SRP_DEFAULT_HASH;
17150 CHAR *loclist = hash_getlist ();
17151 for (i = 0; i < strlen (loclist); i++)
17152 if (hash_supported (hlist, loclist[i])) {
17158 fprintf (stderr, "Unable to agree on hash.\n");
17163 if (!(incrypt = krypto_new (cid, hid, skey, 20, NULL, 0, seqnum,
17167 /* Generate random number for outkey and outseqnum */
17169 t_random (seqnum, 4);
17171 /* Send cid, hid, outkey, outseqnum */
17173 bp = tmp; blen = 0;
17174 srp_put (&cid, &bp, 1, &blen);
17175 srp_put (&hid, &bp, 1, &blen);
17176 srp_put (seqnum, &bp, 4, &blen);
17178 if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE))
17180 reply_parse = "ADAT=";
17181 n = ftpcmd("ADAT",buf,-1,-1,0);
17185 if (!(outcrypt = krypto_new (cid, hid, skey+20, 20, NULL, 0, seqnum,
17189 t_clientclose (tc);
17192 if (n != REPLY_COMPLETE)
17198 printf ("SRP authentication succeeded.\n");
17199 printf ("Using cipher %s and hash function %s.\n",
17200 (cipher_getdescbyid(cid))->name,
17201 (hash_getdescbyid(hid))->name
17204 reply_parse = NULL;
17209 fprintf (stderr, "Base 64 encoding failed: %s.\n", radix_error (e));
17213 fprintf (stderr, "Base 64 decoding failed: %s.\n", radix_error (e));
17217 fprintf (stderr, "Unable to unmarshal authentication data.\n");
17221 fprintf (stderr, "SRP authentication failed, trying regular login.\n");
17222 reply_parse = NULL;
17226 /*--------------------------------------------------------------+
17227 | srp_put: put item to send buffer |
17228 +--------------------------------------------------------------*/
17230 srp_put (in, out, inlen, outlen)
17236 srp_uint32 net_len;
17238 net_len = htonl (inlen);
17239 memcpy (*out, &net_len, 4);
17241 *out += 4; *outlen += 4;
17243 memcpy (*out, in, inlen);
17245 *out += inlen; *outlen += inlen;
17249 /*--------------------------------------------------------------+
17250 | srp_get: get item from receive buffer |
17251 +--------------------------------------------------------------*/
17253 srp_get (in, out, inlen, outlen)
17259 srp_uint32 net_len;
17261 if (*inlen < 4) return -1;
17263 memcpy (&net_len, *in, 4); *inlen -= 4; *in += 4;
17264 *outlen = ntohl (net_len);
17266 if (*inlen < *outlen) return -1;
17268 *out = *in; *inlen -= *outlen; *in += *outlen;
17273 /*--------------------------------------------------------------+
17274 | srp_encode: encode control message |
17275 +--------------------------------------------------------------*/
17277 srp_encode (private, in, out, len)
17284 return krypto_msg_priv (outcrypt, in, out, len);
17286 return krypto_msg_safe (outcrypt, in, out, len);
17289 /*--------------------------------------------------------------+
17290 | srp_decode: decode control message |
17291 +--------------------------------------------------------------*/
17293 srp_decode (private, in, out, len)
17300 return krypto_msg_priv (incrypt, in, out, len);
17302 return krypto_msg_safe (incrypt, in, out, len);
17305 #endif /* FTP_SRP */
17311 The following code is from the Unix FTP client. Be sure to
17312 make sure that the functionality is not lost. Especially
17313 the Proxy stuff even though we have not yet implemented it.
17316 /* Send multiple files */
17319 ftp_mput(argc, argv) int argc; char **argv; {
17326 if (argc < 2 && !another(&argc, &argv, "local-files")) {
17327 printf("usage: %s local-files\n", argv[0]);
17333 oldintr = signal(SIGINT, mcancel);
17335 /* Replace with calls to cc_execute() */
17339 char *cp, *tp2, tmpbuf[CKMAXPATH];
17341 while ((cp = remglob(argv,0)) != NULL) {
17346 if (mflag && confirm(argv[0], cp)) {
17349 while (*tp && !islower(*tp)) {
17355 while ((*tp2 = *tp) != 0) {
17356 if (isupper(*tp2)) {
17357 *tp2 = 'a' + *tp2 - 'A';
17371 sendrequest((sunique) ? "STOU" : "STOR", cp, tp, 0, -1, -1, 0);
17372 if (!mflag && fromatty) {
17373 ointer = interactive;
17375 if (confirm("Continue with","mput")) {
17378 interactive = ointer;
17382 signal(SIGINT, oldintr);
17386 #endif /* FTP_PROXY */
17387 for (i = 1; i < argc; i++) {
17388 register char **cpp, **gargs;
17390 if (mflag && confirm(argv[0], argv[i])) {
17392 sendrequest((ftp_usn) ? "STOU" : "STOR", argv[i], tp, 0,-1,-1, 0);
17393 if (!mflag && fromatty) {
17394 ointer = interactive;
17396 if (confirm("Continue with","mput")) {
17399 interactive = ointer;
17404 gargs = ftpglob(argv[i]);
17405 if (globerr != NULL) {
17406 printf("%s\n", globerr);
17409 free((char *)gargs);
17413 for (cpp = gargs; cpp && *cpp != NULL; cpp++) {
17414 if (mflag && confirm(argv[0], *cpp)) {
17416 sendrequest((sunique) ? "STOU":"STOR", *cpp, tp, 0, -1, -1, 0);
17417 if (!mflag && fromatty) {
17418 ointer = interactive;
17420 if (confirm("Continue with","mput")) {
17423 interactive = ointer;
17427 if (gargs != NULL) {
17429 free((char *)gargs);
17432 signal(SIGINT, oldintr);
17436 /* Get multiple files */
17439 ftp_mget(argc, argv) int argc; char **argv; {
17443 char *cp, *tp, *tp2, tmpbuf[CKMAXPATH];
17446 if (argc < 2 && !another(&argc, &argv, "remote-files")) {
17447 printf("usage: %s remote-files\n", argv[0]);
17453 oldintr = signal(SIGINT,mcancel);
17454 /* Replace with calls to cc_execute() */
17456 while ((cp = remglob(argv,proxy)) != NULL) {
17461 if (mflag && confirm(argv[0], cp)) {
17464 while (*tp && !islower(*tp)) {
17470 while ((*tp2 = *tp) != 0) {
17471 if (isupper(*tp2)) {
17472 *tp2 = 'a' + *tp2 - 'A';
17480 rc = (recvrequest("RETR", tp, cp, "wb",
17481 tp != cp || !interactive) == 0,0,NULL,0,0,0);
17482 if (!mflag && fromatty) {
17483 ointer = interactive;
17485 if (confirm("Continue with","mget")) {
17488 interactive = ointer;
17492 signal(SIGINT,oldintr);
17497 /* Delete multiple files */
17500 mdelete(argc, argv) int argc; char **argv; {
17506 if (argc < 2 && !another(&argc, &argv, "remote-files")) {
17507 printf("usage: %s remote-files\n", argv[0]);
17513 oldintr = signal(SIGINT, mcancel);
17514 /* Replace with calls to cc_execute() */
17516 while ((cp = remglob(argv,0)) != NULL) {
17521 if (mflag && confirm(argv[0], cp)) {
17522 rc = (ftpcmd("DELE",cp,-1,-1,ftp_vbm) == REPLY_COMPLETE);
17523 if (!mflag && fromatty) {
17524 ointer = interactive;
17526 if (confirm("Continue with", "mdelete")) {
17529 interactive = ointer;
17533 signal(SIGINT, oldintr);
17538 /* Get a directory listing of multiple remote files */
17541 mls(argc, argv) int argc; char **argv; {
17544 char *cmd, mode[1], *dest;
17548 if (argc < 2 && !another(&argc, &argv, "remote-files"))
17550 if (argc < 3 && !another(&argc, &argv, "local-file")) {
17552 printf("usage: %s remote-files local-file\n", argv[0]);
17556 dest = argv[argc - 1];
17557 argv[argc - 1] = NULL;
17558 if (strcmp(dest, "-") && *dest != '|')
17559 if (!globulize(&dest) ||
17560 !confirm("output to local-file:", dest)) {
17564 cmd = argv[0][1] == 'l' ? "NLST" : "LIST";
17567 oldintr = signal(SIGINT, mcancel);
17568 /* Replace with calls to cc_execute() */
17570 for (i = 1; mflag && i < argc-1; ++i) {
17571 *mode = (i == 1) ? 'w' : 'a';
17572 rc = recvrequest(cmd, dest, argv[i], mode, 0,0,NULL,0,0,0);
17573 if (!mflag && fromatty) {
17574 ointer = interactive;
17576 if (confirm("Continue with", argv[0])) {
17579 interactive = ointer;
17582 signal(SIGINT, oldintr);
17588 remglob(argv,doswitch) char *argv[]; int doswitch; {
17590 static char buf[CKMAXPATH];
17591 static FILE *ftemp = NULL;
17592 static char **args;
17601 (void) fclose(ftemp);
17610 if ((cp = *++args) == NULL)
17614 if (ftemp == NULL) {
17615 (void) strcpy(temp, _PATH_TMP);
17618 (void) mktemp(temp);
17619 #endif /* MKSTEMP */
17620 #endif /* MKTEMP */
17622 oldhash = hash, hash = 0;
17627 #endif /* FTP_PROXY */
17628 for (mode = "wb"; *++argv != NULL; mode = "ab")
17629 recvrequest ("NLST", temp, *argv, mode, 0);
17634 #endif /* FTP_PROXY */
17636 ftemp = fopen(temp, "r");
17638 if (ftemp == NULL && (!dpyactive || ftp_deb)) {
17639 printf("Can't find list of remote files, oops\n");
17643 if (fgets(buf, CKMAXPATH, ftemp) == NULL) {
17644 fclose(ftemp), ftemp = NULL;
17647 if ((cp = ckstrchr(buf,'\n')) != NULL)
17651 #endif /* NOT_USED */
17652 #endif /* TCPSOCKET (top of file) */
17653 #endif /* SYSFTP (top of file) */
17654 #endif /* NOFTP (top of file) */