1 #define FTP_TIMEOUT
2
3 /* C K C F T P -- FTP Client for C-Kermit */
4
5 char *ckftpv = "FTP Client, 9.0.264, 24 Dec 2015";
6
7 /*
8 Authors:
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.
13
14 Copyright (C) 2000, 2015,
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.
18
19 Portions of conditionally included code Copyright Regents of the
20 University of California and The Stanford SRP Authentication Project;
21 see notices below.
22 */
23
24 /*
25 Pending...
26
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.
31
32 . Make syslog entries for session? Files?
33
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
36 to use stderr.
37
38 . Implement mail (MAIL, MLFL, MSOM, etc) if any servers support it.
39
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).
45 */
46
47 /*
48 Quick FTP command reference:
49
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>
54 PORT - Port
55 PASV - Passive mode
56 USER - User
57 PASS - Password
58 ACCT - Account
59 CWD - Change Working Directory
60 REIN - Logout but not disconnect
61 QUIT - Bye
62 RETR - Retreive
63 STOR - Store
64 APPE - Append
65 ALLO - Allocate
66 REST - Restart
67 RNFR - Rename from
68 RNTO - Rename to
69 ABOR - Cancel
70 DELE - Delete
71 LIST - Directory
72 NLST - Name List
73 SITE - Site parameters or commands
74 STAT - Status
75 HELP - Help
76 NOOP - Noop
77
78 RFC959 (1985):
79 CDUP - Change to Parent Directory
80 SMNT - Structure Mount
81 STOU - Store Unique
82 RMD - Remove Directory
83 MKD - Make Directory
84 PWD - Print Directory
85 SYST - System
86
87 RFC2389 (1998):
88 FEAT - List Features (done)
89 OPTS - Send options (done)
90
91 RFC2640 (1999):
92 LANG - Specify language for messages (not done)
93
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)
100
101 Alphabetical syntax list:
102 ABOR <CRLF>
103 ACCT <SP> <account-information> <CRLF>
104 ALLO <SP> <decimal-integer> [<SP> R <SP> <decimal-integer>] <CRLF>
105 APPE <SP> <pathname> <CRLF>
106 CDUP <CRLF>
107 CWD <SP> <pathname> <CRLF>
108 DELE <SP> <pathname> <CRLF>
109 FEAT <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>
118 NOOP <CRLF>
119 OPTS <SP> <commandname> [ <SP> <command-options> ] <CRLF>
120 PASS <SP> <password> <CRLF>
121 PASV <CRLF>
122 PORT <SP> <host-port> <CRLF>
123 PWD <CRLF>
124 QUIT <CRLF>
125 REIN <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>
136 STOU <CRLF>
137 STRU <SP> <structure-code> <CRLF>
138 SYST <CRLF>
139 TYPE <SP> <type-code> <CRLF>
140 USER <SP> <username> <CRLF>
141 */
142 #include "ckcsym.h" /* Standard includes */
143 #include "ckcdeb.h"
144
145 #ifndef NOFTP /* NOFTP = no FTP */
146 #ifndef SYSFTP /* SYSFTP = use external ftp client */
147 #ifdef TCPSOCKET /* Build only if TCP/IP included */
148 #define CKCFTP_C
149
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. */
152
153 #ifdef CK_ANSIC
154 #include <stdarg.h>
155 #else /* CK_ANSIC */
156 #include <varargs.h>
157 #endif /* CK_ANSIC */
158 #include <signal.h>
159 #ifdef OS2
160 #ifdef OS2ONLY
161 #include <os2.h>
162 #endif /* OS2ONLY */
163 #include "ckowin.h"
164 #include "ckocon.h"
165 #endif /* OS2 */
166 #ifndef ZILOG
167 #ifdef NT
168 #include <setjmpex.h>
169 #ifdef NTSIG
170 extern int TlsIndex;
171 #endif /* NTSIG */
172 #else /* NT */
173 #include <setjmp.h>
174 #endif /* NT */
175 #else
176 #include <setret.h>
177 #endif /* ZILOG */
178 #include "ckcsig.h"
179 #ifdef VMS
180 /* 2010-03-09 SMS. VAX C needs help to find "sys". It's easier not to try. */
181 #include <stat.h>
182 #else /* def VMS */
183 #include <sys/stat.h>
184 #endif /* def VMS [else] */
185 #include <ctype.h>
186
187 #ifndef HPUXPRE65
188 #include <errno.h> /* Error number symbols */
189 #else
190 #ifndef ERRNO_INCLUDED
191 #include <errno.h> /* Error number symbols */
192 #endif /* ERRNO_INCLUDED */
193 #endif /* HPUXPRE65 */
194
195 #ifndef NOTIMEH
196 #include <time.h>
197 #endif /* NOTIMEH */
198 #ifndef EPIPE
199 #define EPIPE 32 /* Broken pipe error */
200 #endif /* EPIPE */
201
202 /* Kermit includes */
203
204 #include "ckcasc.h"
205 #include "ckcker.h"
206 #include "ckucmd.h"
207 #include "ckuusr.h"
208 #include "ckcnet.h" /* Includes ckctel.h */
209 #include "ckctel.h" /* (then why include it again?) */
210 #include "ckcxla.h"
211
212 #ifdef CK_SSL
213 #include "ckuath.h" /* SMS 2007/02/15 */
214 #endif /* def CK_SSL */
215
216 /*
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.
227 */
228 #ifndef DCLTIMEVAL
229 #ifdef SV68R3V6
230 #define DCLTIMEVAL
231 #else
232 #ifdef SCO234
233 #define DCLTIMEVAL
234 #endif /* SCO234 */
235 #endif /* SV68R3V6 */
236 #endif /* DCLTIMEVAL */
237
238 #ifdef DCLTIMEVAL
239 /* Also maybe in some places the elements must be unsigned... */
240 struct timeval {
241 long tv_sec;
242 long tv_usec;
243 };
244 #ifdef COMMENT
245 /* Currently we don't use this... */
246 struct timezone {
247 int tz_minuteswest;
248 int tz_dsttime;
249 };
250 #endif /* COMMENT */
251 #else /* !DCLTIMEVAL */
252 #ifndef NOSYSTIMEH
253 #ifdef SYSTIMEH
254 #include <sys/time.h>
255 #endif /* SYSTIMEH */
256 #endif /* NOSYSTIMEH */
257 #ifndef NOSYSTIMEBH
258 #ifdef SYSTIMEBH
259 #include <sys/timeb.h>
260 #endif /* SYSTIMEBH */
261 #endif /* NOSYSTIMEBH */
262 #endif /* DCLTIMEVAL */
263
264 /* 2010-03-09 SMS. VAX C needs help to find "sys". It's easier not to try. */
265 #ifdef VMS
266 #include <types.h>
267 #else /* def VMS */
268 #include <sys/types.h>
269 #endif /* def VMS [else] */
270 #include <stdio.h>
271 #include <string.h>
272 #ifdef HAVE_STDLIB_H
273 #include <stdlib.h>
274 #endif /* HAVE_STDLIB_H */
275
276 #ifndef NOSETTIME
277 #ifdef COMMENT
278 /* This section moved to ckcdeb.h */
279 #ifdef POSIX
280 #define UTIMEH
281 #else
282 #ifdef HPUX9
283 #define UTIMEH
284 #else
285 #ifdef OS2
286 #define SYSUTIMEH
287 #endif /* OS2 */
288 #endif /* HPUX9 */
289 #endif /* POSIX */
290 #endif /* COMMENT */
291
292 #ifdef VMS /* SMS 2007/02/15 */
293 #include "ckvrtl.h" /* for utime() */
294 #else /* def VMS */
295 #ifdef SYSUTIMEH
296 #include <sys/utime.h>
297 #else
298 #ifdef UTIMEH
299 #include <utime.h>
300 #define SYSUTIMEH
301 #endif /* UTIMEH */
302 #endif /* SYSUTIMEH */
303 #endif /* def VMS */
304 #endif /* NOSETTIME */
305
306 #ifndef SCO_OSR504
307 #ifdef SELECT_H
308 #include <sys/select.h>
309 #endif /* SELECT_H */
310 #endif /* SCO_OSR504 */
311
312 #ifndef INADDR_NONE /* 2010-03-29 */
313 #define INADDR_NONE -1
314 #endif /* INADDR_NONE */
315
316 /* select() dialects... */
317
318 #ifdef UNIX
319 #define BSDSELECT /* BSD select() syntax/semantics */
320 #ifndef FD_SETSIZE
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 */
326 #ifndef howmany
327 #define howmany(x, y) (((x)+((y)-1))/(y))
328 #endif /* howmany */
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)))
334 #endif /* HPUX6 */
335
336 #else
337 #ifdef OS2 /* OS/2 or Win32 */
338 #ifdef NT
339 #define BSDSELECT
340 #else /* NT */
341 #define IBMSELECT
342 #endif /* NT */
343 #endif /* OS2 */
344 #endif /* UNIX */
345
346 #ifdef VMS
347 #define BSDSELECT /* SMS 2007/02/15 */
348 #endif /* def VMS */
349
350 /* Other select() peculiarities */
351
352 #ifdef HPUX
353 #ifndef HPUX10 /* HP-UX 9.xx and earlier */
354 #ifndef HPUX1100
355 /* The three interior args to select() are (int *) rather than (fd_set *) */
356 #ifndef INTSELECT
357 #define INTSELECT
358 #endif /* INTSELECT */
359 #endif /* HPUX1100 */
360 #endif /* HPUX10 */
361 #endif /* HPUX */
362
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
372 #define bind Rbind
373 #define connect Rconnect
374 #define getsockname Rgetsockname
375 #define listen Rlisten
376 #endif /* CK_SOCKS5 */
377 #endif /* CK_SOCKS */
378
379 #ifndef NOHTTP
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];
387 #endif /* NOHTTP */
388 int ssl_ftp_proxy = 0; /* FTP over SSL/TLS Proxy Server */
389
390 /* Feature selection */
391
392 #ifndef USE_SHUTDOWN
393 /*
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.
397 */
398 /* #define USE_SHUTDOWN */
399 #endif /* USE_SHUTDOWN */
400
401 #ifndef NORESEND
402 #ifndef NORESTART /* Restart / recover */
403 #ifndef FTP_RESTART
404 #define FTP_RESTART
405 #endif /* FTP_RESTART */
406 #endif /* NORESTART */
407 #endif /* NORESEND */
408
409 #ifndef NOUPDATE /* Update mode */
410 #ifndef DOUPDATE
411 #define DOUPDATE
412 #endif /* DOUPDATE */
413 #endif /* NOUPDATE */
414
415 #ifndef UNICODE /* Unicode required */
416 #ifndef NOCSETS /* for charset translation */
417 #define NOCSETS
418 #endif /* NOCSETS */
419 #endif /* UNICODE */
420
421 #ifndef OS2
422 #ifndef HAVE_MSECS /* Millisecond timer */
423 #ifdef UNIX
424 #ifdef GFTIMER
425 #define HAVE_MSECS
426 #endif /* GFTIMER */
427 #endif /* UNIX */
428 #endif /* HAVE_MSECS */
429 #endif /* OS2 */
430
431 #ifdef PIPESEND /* PUT from pipe */
432 #ifndef PUTPIPE
433 #define PUTPIPE
434 #endif /* PUTPIPE */
435 #endif /* PIPESEND */
436
437 #ifndef NOSPL /* PUT from array */
438 #ifndef PUTARRAY
439 #define PUTARRAY
440 #endif /* PUTARRAY */
441 #endif /* NOSPL */
442
443 /* Security... */
444
445 #ifdef CK_SRP
446 #define FTP_SRP
447 #endif /* CK_SRP */
448
449 #ifdef CK_KERBEROS
450 #ifdef KRB4
451 /*
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.
456 */
457 #ifdef KRB524
458 #define FTP_KRB4
459 #else /* KRB524 */
460 #ifndef CK_SSL
461 #ifndef LIBDES
462 #define FTP_KRB4
463 #endif /* LIBDES */
464 #endif /* CK_SSL */
465 #endif /* KRB524 */
466 #endif /* KRB4 */
467 #ifdef KRB5
468 #ifndef HEIMDAL
469 #ifndef NOFTP_GSSAPI /* 299 */
470 #define FTP_GSSAPI
471 #endif /* NOFTP_GSSAPI */
472 #endif /* HEIMDAL */
473 #endif /* KRB5 */
474 #endif /* CK_KERBEROS */
475
476 /* FTP_SECURITY is defined if any of the above is selected */
477 #ifndef FTP_SECURITY
478 #ifdef FTP_GSSAPI
479 #define FTP_SECURITY
480 #else
481 #ifdef FTP_KRB4
482 #define FTP_SECURITY
483 #else
484 #ifdef FTP_SRP
485 #define FTP_SECURITY
486 #else
487 #ifdef CK_SSL
488 #define FTP_SECURITY
489 #endif /* CK_SSL */
490 #endif /* FTP_SRP */
491 #endif /* FTP_KRB4 */
492 #endif /* FTP_GSSAPI */
493 #endif /* FTP_SECURITY */
494
495 #ifdef CK_DES
496 #ifdef CK_SSL
497 #ifndef LIBDES
498 #define LIBDES
499 #endif /* LIBDES */
500 #endif /* CK_SSL */
501 #endif /* CK_DES */
502
503 #ifdef CRYPT_DLL
504 #ifndef LIBDES
505 #define LIBDES
506 #endif /* LIBDES */
507 #endif /* CRYPT_DLL */
508
509 #ifdef FTP_KRB4
510 #define des_cblock Block
511 #define des_key_schedule Schedule
512 #ifdef KRB524
513 #ifdef NT
514 #define _WINDOWS
515 #endif /* NT */
516 #include "kerberosIV/krb.h"
517 #else /* KRB524 */
518 #ifdef SOLARIS
519 #ifndef sun
520 /* For some reason lost in history the Makefile Solaris targets have -Usun */
521 #define sun
522 #endif /* sun */
523 #endif /* SOLARIS */
524 #include "krb.h"
525 #define krb_get_err_text_entry krb_get_err_text
526 #endif /* KRB524 */
527 #endif /* FTP_KRB4 */
528
529 #ifdef CK_SSL
530 #ifdef FTP_KRB4
531 #ifndef HEADER_DES_H
532 #define HEADER_DES_H
533 #endif /* HEADER_DES_H */
534 #endif /* FTP_KRB4 */
535 #include "ck_ssl.h"
536 #endif /* CK_SSL */
537
538 #ifdef FTP_SRP
539 #ifdef HAVE_PWD_H
540 #include "pwd.h"
541 #endif /* HAVE_PWD_H */
542 #include "t_pwd.h"
543 #include "t_client.h"
544 #include "krypto.h"
545 #endif /* FTP_SRP */
546
547 #ifdef FTP_GSSAPI
548 #include <gssapi/gssapi.h>
549 /*
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.
553 */
554 #include <gssapi/gssapi_generic.h>
555 #include <gssapi/gssapi_krb5.h>
556 static gss_ctx_id_t gcontext;
557
558 #ifdef MACOSX
559 /** exported constants defined in gssapi_krb5{,_nx}.h **/
560
561 /* these are bogus, but will compile */
562
563 /*
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
579 *
580 */
581
582 /*
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.
587 */
588
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"},
600 { 0, 0 }
601 };
602
603 static
604 CONST gss_OID_desc * CONST gss_mech_krb5_v2 = ck_krb5_gss_oid_array+2;
605
606 #ifdef MACOSX103
607 static
608 CONST gss_OID_desc * CONST gss_mech_krb5 = ck_krb5_gss_oid_array+0;
609 #endif /* MACOSX103 */
610
611 #ifndef MACOSX
612 static
613 CONST gss_OID_desc * CONST gss_mech_krb5 = ck_krb5_gss_oid_array+0;
614 static
615 CONST gss_OID_desc * CONST gss_mech_krb5_old = ck_krb5_gss_oid_array+1;
616 static
617 CONST gss_OID_desc * CONST gss_nt_krb5_name = ck_krb5_gss_oid_array+3;
618 static
619 CONST gss_OID_desc * CONST gss_nt_krb5_principal = ck_krb5_gss_oid_array+4;
620 #endif /* MACOSX */
621
622 /*
623 * See krb5/gssapi_krb5.c for a description of the algorithm for
624 * encoding an object identifier.
625 */
626
627 /*
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
631 * machine_uid_name:
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
634 * string_uid_name:
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
637 * service_name:
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
640 * exported_name:
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)
646 */
647
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"},
655 };
656
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;
663 #endif /* MACOSX */
664 #endif /* FTP_GSSAPI */
665
666 #ifdef OS2
667 #ifdef FTP_SRP
668 #define MAP_KRYPTO
669 #ifdef SRPDLL
670 #define MAP_SRP
671 #endif /* SRPDLL */
672 #endif /* FTP_SRP */
673 #ifdef FTP_KRB4
674 #define MAP_KRB4
675 #ifdef CK_ENCRYPTION
676 #define MAP_DES
677 #endif /* CK_ENCRYPTION */
678 #endif /* FTP_KRB4 */
679 #ifdef FTP_GSSAPI
680 #define MAP_GSSAPI
681 #define GSS_OIDS
682 #endif /* FTP_GSSAPI */
683 #include "ckoath.h"
684
685 extern int k95stdout, wherex[], wherey[];
686 extern unsigned char colorcmd;
687 #endif /* OS2 */
688
689 #ifdef FTP_KRB4
690 static char ftp_realm[REALM_SZ + 1];
691 static KTEXT_ST ftp_tkt;
692 #ifdef OS2
693 static LEASH_CREDENTIALS ftp_cred;
694 #else /* OS2 */
695 static CREDENTIALS ftp_cred;
696 #endif /* OS2 */
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 */
701
702 /* getreply() function codes */
703
704 #define GRF_AUTH 1 /* Reply to AUTH command */
705 #define GRF_FEAT 2 /* Reply to FEAT command */
706
707 /* Operational definitions */
708
709 #define DEF_VBM 0 /* Default verbose mode */
710 /* #define SETVBM */ /* (see getreply) */
711
712 #define URL_ONEFILE /* GET, not MGET, for FTP URL */
713
714 #define FTP_BUFSIZ 10240 /* Max size for FTP cmds & replies */
715 #define SRVNAMLEN 32 /* Max length for server type name */
716 #define PWDSIZ 256
717 #define PASSBUFSIZ 256
718 #define PROMPTSIZ 256
719
720 #ifndef MGETMAX /* Max operands for MGET command */
721 #define MGETMAX 1000
722 #endif /* MGETMAX */
723
724 #ifdef FTP_SRP
725 #define FUDGE_FACTOR 100
726 #endif /* FTP_SRP */
727
728 /*
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.
733 */
734 #ifdef FTP_GSSAPI
735 #ifndef FUDGE_FACTOR
736 #define FUDGE_FACTOR 96
737 #endif /* FUDGE_FACTOR */
738 #endif /* FTP_GSSAPI */
739
740 #ifdef FTP_KRB4
741 #ifndef FUDGE_FACTOR
742 #define FUDGE_FACTOR 32
743 #endif /* FUDGE_FACTOR */
744 #endif /* FTP_KRB4 */
745
746 #ifndef FUDGE_FACTOR /* In case no auth types define it */
747 #define FUDGE_FACTOR 0
748 #endif /* FUDGE_FACTOR */
749
750 #ifndef MAXHOSTNAMELEN
751 #define MAXHOSTNAMELEN 64
752 #endif /* MAXHOSTNAMELEN */
753 #define MAX_DNS_NAMELEN (15*(MAXHOSTNAMELEN + 1)+1)
754
755 /* Fascist compiler toadying */
756
757 #ifndef SENDARG2TYPE
758 #ifdef COMMENT /* Might be needed here and there */
759 #define SENDARG2TYPE const char *
760 #else
761 #define SENDARG2TYPE char *
762 #endif /* COMMENT */
763 #endif /* SENDARG2TYPE */
764
765 /* Common text messages */
766
767 static char *nocx = "?No FTP control connection\n";
768
769 static char *fncnam[] = {
770 "rename", "overwrite", "backup", "append", "discard", "ask", "update",
771 "dates-differ", ""
772 };
773
774 /* Macro definitions */
775
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)))
779
780 #define CHECKCONN() if(!connected){printf(nocx);return(-9);}
781
782 /* Externals */
783
784 #ifdef CK_URL
785 extern struct urldata g_url;
786 #endif /* CK_URL */
787
788 #ifdef DYNAMIC
789 extern char *zinbuffer, *zoutbuffer; /* Regular Kermit file i/o */
790 #else
791 extern char zinbuffer[], zoutbuffer[];
792 #endif /* DYNAMIC */
793 extern char *zinptr, *zoutptr;
794 extern int zincnt, zoutcnt, zobufsize, fncact;
795
796 #ifdef CK_TMPDIR
797 extern int f_tmpdir; /* Directory changed temporarily */
798 extern char savdir[]; /* For saving current directory */
799 extern char * dldir;
800 #endif /* CK_TMPDIR */
801
802 extern char * rfspec, * sfspec, * srfspec, * rrfspec; /* For WHERE command */
803
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;
813
814 #ifdef FTP_TIMEOUT
815 int ftp_timed_out = 0;
816 long ftp_timeout = 0;
817 #endif /* FTP_TIMEOUT */
818
819 #ifdef GFTIMER
820 extern CKFLOAT fptsecs, fpfsecs, fpxfsecs;
821 #else
822 extern long xfsecs;
823 #endif /* GFTIMER */
824
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;
829
830 #ifdef LOCUS
831 extern int locus, autolocus;
832 #endif /* LOCUS */
833
834 #ifndef NOCSETS
835 extern int nfilc, dcset7, dcset8, fileorder;
836 extern struct csinfo fcsinfo[];
837 extern struct keytab fcstab[];
838 extern int fcharset;
839 #endif /* NOCSETS */
840
841 extern char sndbefore[], sndafter[], *sndexcept[]; /* Selection criteria */
842 extern char sndnbefore[], sndnafter[], *rcvexcept[];
843 extern CHAR feol;
844
845 extern char * remdest;
846 extern int remfile, remappd, rempipe;
847
848 #ifndef NOSPL
849 extern int cmd_quoting;
850 #ifdef PUTARRAY
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 */
856 #endif /* NOSPL */
857
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;
864 extern int addlist;
865 extern char fspec[]; /* Most recent filespec */
866 extern int fspeclen; /* Length of fspec[] buffer */
867 #endif /* NOMSEND */
868
869 extern int pipesend;
870 #ifdef PIPESEND
871 extern char * sndfilter, * rcvfilter;
872 #endif /* PIPESEND */
873
874 #ifdef CKROOT
875 extern int ckrooterr;
876 #endif /* CKROOT */
877
878 #ifdef KRB4
879 extern int krb4_autoget;
880 _PROTOTYP(char * ck_krb4_realmofhost,(char *));
881 #endif /* KRB4 */
882
883 #ifdef KRB5
884 extern int krb5_autoget;
885 extern int krb5_d_no_addresses;
886 _PROTOTYP(char * ck_krb5_realmofhost,(char *));
887 #endif /* KRB5 */
888
889 #ifdef DCMDBUF
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 */
894 #else
895 extern char atmbuf[]; /* The same, but static */
896 extern char cmdbuf[];
897 extern char line[];
898 extern char tmpbuf[];
899 #endif /* DCMDBUF */
900
901 extern char * cmarg, * cmarg2, ** cmlist; /* For setting up file lists */
902
903 /* Public variables declared here */
904
905 #ifdef NOXFER
906 int ftpget = 1; /* GET/PUT/REMOTE orientation FTP */
907 #else
908 int ftpget = 2; /* GET/PUT/REMOTE orientation AUTO */
909 #endif /* NOXFER */
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 */
916 int sav_log = -1;
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 */
920
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 */
928
929 /* Definitions and typedefs needed for prototypes */
930
931 #define sig_t my_sig_t
932 #define sigtype SIGTYP
933 typedef sigtype (*sig_t)();
934
935 /* Static global variables */
936
937 static char ftpsndbuf[FTP_BUFSIZ+64];
938
939 static char * fts_sto = NULL;
940
941 static int ftpsndret = 0;
942 static struct _ftpsnd {
943 sig_t oldintr, oldintp;
944 int reply;
945 int incs,
946 outcs;
947 char * cmd, * local, * remote;
948 int bytes;
949 int restart;
950 int xlate;
951 char * lmode;
952 } ftpsnd;
953
954 /*
955 This is just a first stab -- these strings should match how the
956 corresponding FTP servers identify themselves.
957 */
958 #ifdef UNIX
959 static char * myostype = "UNIX";
960 #else
961 #ifdef VMS
962 /* not yet... */
963 static char * myostype = "VMS";
964 #else
965 #ifdef OS2
966 #ifdef NT
967 static char * myostype = "WIN32";
968 #else
969 static char * myostype = "OS/2";
970 #endif /* NT */
971 #else
972 static char * myostype = "UNSUPPORTED";
973 #endif /* OS2 */
974 #endif /* VMS */
975 #endif /* UNIX */
976
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;
1007
1008 static int i, /* j, k, */ x, y, z; /* Volatile temporaries */
1009 static int c0, c1; /* Temp variables for characters */
1010
1011 static char putpath[CKMAXPATH+1] = { NUL, NUL };
1012 static char asnambuf[CKMAXPATH+1] = { NUL, NUL };
1013
1014 #define RFNBUFSIZ 4096 /* Remote filename buffer size */
1015
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 */
1020
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;
1026
1027 /* Protection level symbols */
1028
1029 #define FPL_CLR 1 /* Clear */
1030 #define FPL_SAF 2 /* Safe */
1031 #define FPL_PRV 3 /* Private */
1032 #define FPL_CON 4 /* Confidential */
1033
1034 /* Symbols for file types returned by MLST/MLSD */
1035
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 */
1040
1041 /* File type symbols keyed to the file-type symbols from ckcker.h */
1042
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) */
1046
1047 /* Server feature table - sfttab[0] > 0 means server supports FEAT and OPTS */
1048
1049 static int sfttab[16] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
1050
1051 #define SFT_AUTH 1 /* FTP server feature codes */
1052 #define SFT_LANG 2
1053 #define SFT_MDTM 3
1054 #define SFT_MLST 4
1055 #define SFT_PBSZ 5
1056 #define SFT_PROT 6
1057 #define SFT_REST 7
1058 #define SFT_SIZE 8
1059 #define SFT_TVFS 9
1060 #define SFT_UTF8 10
1061
1062 #define CNV_AUTO 2 /* FTP filename conversion */
1063 #define CNV_CNV 1
1064 #define CNV_LIT 0
1065
1066 /* SET FTP values */
1067
1068 static int /* SET FTP values... */
1069 ftp_aut = 1, /* Auto-authentication */
1070 #ifdef FTP_SECURITY
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 */
1076 #ifdef FTP_PROXY
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 */
1092
1093 #ifdef CK_SSL
1094 static int ftp_bug_use_ssl_v2 = 0; /* use SSLv2 for AUTH SSL */
1095 static int ftp_bug_use_ssl_v3 = 0; /* use SSLv3 for AUTH SSL */
1096 #endif /* CK_SSL */
1097
1098 static int
1099 #ifdef NOCSETS
1100 ftp_csr = -1, /* Remote (server) character set */
1101 #else
1102 ftp_csr = FC_UTF8,
1103 #endif /* NOCSETS */
1104 ftp_xla = 0; /* Character-set translation on/off */
1105 int
1106 ftp_csx = -1, /* Remote charset currently in use */
1107 ftp_csl = -1; /* Local charset currently in use */
1108
1109 static int g_ftp_typ = FTT_ASC; /* For saving and restoring ftp_typ */
1110
1111 char * ftp_nml = NULL; /* /NAMELIST */
1112 char * ftp_tmp = NULL; /* Temporary string */
1113 static char * ftp_acc = NULL; /* Account string */
1114 static char * auth_type = NULL; /* Authentication type */
1115 static char * srv_renam = NULL; /* Server-rename string */
1116 FILE * fp_nml = NULL; /* Namelist file pointer */
1117
1118 static int csocket = -1; /* Control socket */
1119 static int connected = 0; /* Connected to FTP server */
1120 /* static unsigned short ftp_port = 0; */ /* FTP port */
1121 /* static int ftp_port = 0; */ /* SMS 2007/02/15 */
1122 static int ftp_port = 0; /* fdc 2007/08/30 */
1123 #ifdef FTPHOST
1124 static int hostcmd = 0; /* Has HOST command been sent */
1125 #endif /* FTPHOST */
1126 static int form, mode, stru, bytesize, curtype = FTT_ASC;
1127 static char bytename[8];
1128
1129 /* For parsing replies to FTP server command */
1130 static char *reply_parse, reply_buf[FTP_BUFSIZ], *reply_ptr;
1131
1132 #ifdef FTP_PROXY
1133 static int proxy, unix_proxy
1134 #endif /* FTP_PROXY */
1135
1136 static char pasv[64]; /* Passive-mode port */
1137 static int passivemode = 0;
1138 static int sendport = 0;
1139 static int servertype = 0; /* FTP server's OS type */
1140
1141 static int testing = 0;
1142 static char ftpcmdbuf[FTP_BUFSIZ];
1143
1144 /* Macro definitions */
1145
1146 #define UC(b) ckitoa(((int)b)&0xff)
1147 #define nz(x) ((x) == 0 ? 1 : (x))
1148
1149 /* Command tables and definitions */
1150
1151 #define FTP_ACC 1 /* FTP command keyword codes */
1152 #define FTP_APP 2
1153 #define FTP_CWD 3
1154 #define FTP_CHM 4
1155 #define FTP_CLS 5
1156 #define FTP_DEL 6
1157 #define FTP_DIR 7
1158 #define FTP_GET 8
1159 #define FTP_IDL 9
1160 #define FTP_MDE 10
1161 #define FTP_MDI 11
1162 #define FTP_MGE 12
1163 #define FTP_MKD 13
1164 #define FTP_MOD 14
1165 #define FTP_MPU 15
1166 #define FTP_OPN 16
1167 #define FTP_PUT 17
1168 #define FTP_PWD 18
1169 #define FTP_RGE 19
1170 #define FTP_REN 20
1171 #define FTP_RES 21
1172 #define FTP_HLP 22
1173 #define FTP_RMD 23
1174 #define FTP_STA 24
1175 #define FTP_SIT 25
1176 #define FTP_SIZ 26
1177 #define FTP_SYS 27
1178 #define FTP_UMA 28
1179 #define FTP_GUP 29
1180 #define FTP_USR 30
1181 #define FTP_QUO 31
1182 #define FTP_TYP 32
1183 #define FTP_FEA 33
1184 #define FTP_OPT 34
1185 #define FTP_CHK 35
1186 #define FTP_VDI 36
1187 #define FTP_ENA 37
1188 #define FTP_DIS 38
1189 #define FTP_REP 39
1190
1191 struct keytab gprtab[] = { /* GET-PUT-REMOTE keywords */
1192 { "auto", 2, 0 },
1193 { "ftp", 1, 0 },
1194 { "kermit", 0, 0 }
1195 };
1196
1197 static struct keytab qorp[] = { /* QUIT or PROCEED keywords */
1198 { "proceed", 0, 0 }, /* 0 = proceed */
1199 { "quit", 1, 0 } /* 1 = quit */
1200 };
1201
1202 static struct keytab ftpcmdtab[] = { /* FTP command table */
1203 { "account", FTP_ACC, 0 },
1204 { "append", FTP_APP, 0 },
1205 { "bye", FTP_CLS, 0 },
1206 { "cd", FTP_CWD, 0 },
1207 { "cdup", FTP_GUP, 0 },
1208 { "check", FTP_CHK, 0 },
1209 { "chmod", FTP_CHM, 0 },
1210 { "close", FTP_CLS, 0 },
1211 { "cwd", FTP_CWD, CM_INV },
1212 { "delete", FTP_MDE, 0 },
1213 { "directory", FTP_DIR, 0 },
1214 { "disable", FTP_DIS, 0 },
1215 { "enable", FTP_ENA, 0 },
1216 { "features", FTP_FEA, 0 },
1217 { "get", FTP_GET, 0 },
1218 { "help", FTP_HLP, 0 },
1219 { "idle", FTP_IDL, 0 },
1220 { "login", FTP_USR, CM_INV },
1221 { "mdelete", FTP_MDE, CM_INV },
1222 { "mget", FTP_MGE, 0 },
1223 { "mkdir", FTP_MKD, 0 },
1224 { "modtime", FTP_MOD, 0 },
1225 { "mput", FTP_MPU, 0 },
1226 { "open", FTP_OPN, 0 },
1227 { "opt", FTP_OPT, CM_INV|CM_ABR },
1228 { "opts", FTP_OPT, CM_INV },
1229 { "options", FTP_OPT, 0 },
1230 { "put", FTP_PUT, 0 },
1231 { "pwd", FTP_PWD, 0 },
1232 { "quit", FTP_CLS, CM_INV },
1233 { "quote", FTP_QUO, 0 },
1234 { "reget", FTP_RGE, 0 },
1235 { "rename", FTP_REN, 0 },
1236 { "reput", FTP_REP, 0 },
1237 { "resend", FTP_REP, CM_INV },
1238 { "reset", FTP_RES, 0 },
1239 { "rmdir", FTP_RMD, 0 },
1240 { "send", FTP_PUT, CM_INV },
1241 { "site", FTP_SIT, 0 },
1242 { "size", FTP_SIZ, 0 },
1243 { "status", FTP_STA, 0 },
1244 { "system", FTP_SYS, 0 },
1245 { "type", FTP_TYP, 0 },
1246 { "umask", FTP_UMA, 0 },
1247 { "up", FTP_GUP, CM_INV },
1248 { "user", FTP_USR, 0 },
1249 { "vdirectory",FTP_VDI, 0 },
1250 { "", 0, 0 }
1251 };
1252 static int nftpcmd = (sizeof(ftpcmdtab) / sizeof(struct keytab)) - 1;
1253
1254 #define OPN_ANO 1 /* FTP OPEN switch codes */
1255 #define OPN_PSW 2
1256 #define OPN_USR 3
1257 #define OPN_ACC 4
1258 #define OPN_ACT 5
1259 #define OPN_PSV 6
1260 #define OPN_TLS 7
1261 #define OPN_NIN 8
1262 #define OPN_NOL 9
1263
1264 #ifdef FTP_SECURITY
1265 #ifdef CK_SSL
1266 #define USETLSTAB
1267 static struct keytab tlstab[] = { /* FTP SSL/TLS switches */
1268 { "/ssl", OPN_TLS, 0 },
1269 { "/tls", OPN_TLS, 0 },
1270 { "", 0, 0 }
1271 };
1272 static int ntlstab = (sizeof(tlstab) / sizeof(struct keytab)) - 1;
1273 #endif /* CK_SSL */
1274 #endif /* FTP_SECURITY */
1275
1276 static struct keytab ftpswitab[] = { /* FTP command switches */
1277 { "/account", OPN_ACC, CM_ARG },
1278 { "/active", OPN_ACT, 0 },
1279 { "/anonymous", OPN_ANO, 0 },
1280 { "/noinit", OPN_NIN, 0 },
1281 { "/nologin", OPN_NOL, 0 },
1282 { "/passive", OPN_PSV, 0 },
1283 { "/password", OPN_PSW, CM_ARG },
1284 { "/user", OPN_USR, CM_ARG },
1285 { "", 0, 0 }
1286 };
1287 static int nftpswi = (sizeof(ftpswitab) / sizeof(struct keytab)) - 1;
1288
1289 /* FTP { ENABLE, DISABLE } items */
1290
1291 #define ENA_FEAT 1
1292 #define ENA_MDTM 2
1293 #define ENA_MLST 3
1294 #define ENA_SIZE 4
1295 #define ENA_AUTH 5
1296
1297 static struct keytab ftpenatab[] = {
1298 { "AUTH", ENA_AUTH, 0 },
1299 { "FEAT", ENA_FEAT, 0 },
1300 { "MDTM", ENA_MDTM, 0 },
1301 { "ML", ENA_MLST, CM_INV|CM_ABR },
1302 { "MLS", ENA_MLST, CM_INV|CM_ABR },
1303 { "MLSD", ENA_MLST, CM_INV },
1304 { "MLST", ENA_MLST, 0 },
1305 { "SIZE", ENA_SIZE, 0 },
1306 { "", 0, 0 }
1307 };
1308 static int nftpena = (sizeof(ftpenatab) / sizeof(struct keytab)) - 1;
1309
1310 /* SET FTP command keyword indices */
1311
1312 #define FTS_AUT 1 /* Autoauthentication */
1313 #define FTS_CRY 2 /* Encryption */
1314 #define FTS_LOG 3 /* Autologin */
1315 #define FTS_CPL 4 /* Command protection level */
1316 #define FTS_CFW 5 /* Credentials forwarding */
1317 #define FTS_DPL 6 /* Data protection level */
1318 #define FTS_DBG 7 /* Debugging */
1319 #define FTS_PSV 8 /* Passive mode */
1320 #define FTS_SPC 9 /* Send port commands */
1321 #define FTS_TYP 10 /* (file) Type */
1322 #define FTS_USN 11 /* Unique server names (for files) */
1323 #define FTS_VBM 12 /* Verbose mode */
1324 #define FTS_ATP 13 /* Authentication type */
1325 #define FTS_CNV 14 /* Filename conversion */
1326 #define FTS_TST 15 /* Test (progress) messages */
1327 #define FTS_PRM 16 /* (file) Permissions */
1328 #define FTS_XLA 17 /* Charset translation */
1329 #define FTS_CSR 18 /* Server charset */
1330 #define FTS_ERR 19 /* Error action */
1331 #define FTS_FNC 20 /* Collision */
1332 #define FTS_SRP 21 /* SRP options */
1333 #define FTS_GFT 22 /* GET automatic file-type switching */
1334 #define FTS_DAT 23 /* Set file dates */
1335 #define FTS_STO 24 /* Server time offset */
1336 #define FTS_APW 25 /* Anonymous password */
1337 #define FTS_DIS 26 /* File-transfer display style */
1338 #define FTS_BUG 27 /* Bug(s) */
1339 #define FTS_TMO 28 /* Timeout */
1340
1341 /* FTP BUGS */
1342
1343 #define FTB_SV2 1 /* use SSLv2 */
1344 #define FTB_SV3 2 /* use SSLv3 */
1345
1346 static struct keytab ftpbugtab[] = {
1347 { "use-ssl-v2", FTB_SV2, 0 },
1348 { "use-ssl-v3", FTB_SV3, 0 }
1349
1350 };
1351 static int nftpbug = (sizeof(ftpbugtab) / sizeof(struct keytab));
1352
1353 /* FTP PUT options (mutually exclusive, not a bitmask) */
1354
1355 #define PUT_UPD 1 /* Update */
1356 #define PUT_RES 2 /* Restart */
1357 #define PUT_SIM 4 /* Simulation */
1358 #define PUT_DIF 8 /* Dates Differ */
1359
1360 static struct keytab ftpcolxtab[] = { /* SET FTP COLLISION options */
1361 #ifndef MAC
1362 { "append", XYFX_A, 0 }, /* append to old file */
1363 #endif /* MAC */
1364 #ifdef COMMENT
1365 { "ask", XYFX_Q, 0 }, /* ask what to do (not implemented) */
1366 #endif
1367 { "backup", XYFX_B, 0 }, /* rename old file */
1368 #ifndef MAC
1369 { "dates-differ", XYFX_M, 0 }, /* accept if dates differ */
1370 { "discard", XYFX_D, 0 }, /* don't accept new file */
1371 { "no-supersede", XYFX_D, CM_INV }, /* ditto (MSK compatibility) */
1372 #endif /* MAC */
1373 { "overwrite", XYFX_X, 0 }, /* overwrite the old file */
1374 { "rename", XYFX_R, 0 }, /* rename the incoming file */
1375 #ifndef MAC /* This crashes Mac Kermit. */
1376 { "update", XYFX_U, 0 }, /* replace if newer */
1377 #endif /* MAC */
1378 { "", 0, 0 }
1379 };
1380 static int nftpcolx = (sizeof(ftpcolxtab) / sizeof(struct keytab)) - 1;
1381
1382
1383 #ifdef FTP_SECURITY
1384 /* FTP authentication options */
1385
1386 #define FTA_AUTO 0 /* Auto */
1387 #define FTA_SRP 1 /* SRP */
1388 #define FTA_GK5 2 /* Kerberos 5 */
1389 #define FTA_K4 3 /* Kerberos 4 */
1390 #define FTA_SSL 4 /* SSL */
1391 #define FTA_TLS 5 /* TLS */
1392
1393 /* FTP authentication types */
1394
1395 #define FTPATYPS 8
1396 static int ftp_auth_type[FTPATYPS] = {
1397 #ifdef FTP_GSSAPI
1398 FTA_GK5, /* GSSAPI Kerberos 5 */
1399 #endif /* FTP_GK5 */
1400 #ifdef FTP_SRP
1401 FTA_SRP, /* SRP */
1402 #endif /* FTP_SRP */
1403 #ifdef FTP_KRB4
1404 FTA_K4, /* Kerberos 4 */
1405 #endif /* FTP_KRB4 */
1406 #ifdef CK_SSL
1407 FTA_TLS, /* TLS */
1408 FTA_SSL, /* SSL */
1409 #endif /* CK_SSL */
1410 0
1411 };
1412
1413 static struct keytab ftpauth[] = { /* SET FTP AUTHTYPE cmd table */
1414 { "automatic", FTA_AUTO, CM_INV },
1415 #ifdef FTP_GSSAPI
1416 { "gssapi-krb5", FTA_GK5, 0 },
1417 #endif /* FTP_GSSAPI */
1418 #ifdef FTP_KRB4
1419 { "k4", FTA_K4, CM_INV },
1420 #endif /* FTP_KRB4 */
1421 #ifdef FTP_GSSAPI
1422 { "k5", FTA_GK5, CM_INV },
1423 #endif /* FTP_GSSAPI */
1424 #ifdef FTP_KRB4
1425 { "kerberos4", FTA_K4, 0 },
1426 #endif /* FTP_KRB4 */
1427 #ifdef FTP_GSSAPI
1428 { "kerberos5", FTA_GK5, CM_INV },
1429 #endif /* FTP_GSSAPI */
1430 #ifdef FTP_KRB4
1431 { "kerberos_iv",FTA_K4, CM_INV },
1432 #endif /* FTP_KRB4 */
1433 #ifdef FTP_GSSAPI
1434 { "kerberos_v", FTA_GK5, CM_INV },
1435 #endif /* FTP_GSSAPI */
1436 #ifdef FTP_KRB4
1437 { "krb4", FTA_K4, CM_INV },
1438 #endif /* FTP_KRB4 */
1439 #ifdef FTP_GSSAPI
1440 { "krb5", FTA_GK5, CM_INV },
1441 #endif /* FTP_GSSAPI */
1442 #ifdef FTP_SRP
1443 { "srp", FTA_SRP, 0 },
1444 #endif /* FTP_SRP */
1445 #ifdef CK_SSL
1446 { "ssl", FTA_SSL, 0 },
1447 { "tls", FTA_TLS, 0 },
1448 #endif /* CK_SSL */
1449 { "", 0, 0 }
1450 };
1451 static int nftpauth = (sizeof(ftpauth) / sizeof(struct keytab)) - 1;
1452
1453 #ifdef FTP_SRP
1454 #define SRP_CIPHER 1
1455 #define SRP_HASH 2
1456 static struct keytab ftpsrp[] = { /* SET FTP SRP command table */
1457 { "cipher", SRP_CIPHER, 0 },
1458 { "hash", SRP_HASH, 0 },
1459 { "", 0, 0 }
1460 };
1461 static int nftpsrp = (sizeof(ftpsrp) / sizeof(struct keytab)) - 1;
1462 #endif /* FTP_SRP */
1463 #endif /* FTP_SECURITY */
1464
1465 static struct keytab ftpset[] = { /* SET FTP commmand table */
1466 { "anonymous-password", FTS_APW, 0 },
1467 #ifdef FTP_SECURITY
1468 { "authtype", FTS_ATP, 0 },
1469 { "autoauthentication", FTS_AUT, 0 },
1470 { "autoencryption", FTS_CRY, 0 },
1471 #endif /* FTP_SECURITY */
1472 { "autologin", FTS_LOG, 0 },
1473 { "bug", FTS_BUG, 0 },
1474 #ifndef NOCSETS
1475 { "character-set-translation",FTS_XLA, 0 },
1476 #endif /* NOCSETS */
1477 { "collision", FTS_FNC, 0 },
1478 #ifdef FTP_SECURITY
1479 { "command-protection-level", FTS_CPL, 0 },
1480 { "cpl", FTS_CPL, CM_INV },
1481 { "credential-forwarding", FTS_CFW, 0 },
1482 { "da", FTS_DAT, CM_INV|CM_ABR },
1483 { "data-protection-level", FTS_DPL, 0 },
1484 #endif /* FTP_SECURITY */
1485 { "dates", FTS_DAT, 0 },
1486 { "debug", FTS_DBG, 0 },
1487 { "display", FTS_DIS, 0 },
1488 #ifdef FTP_SECURITY
1489 { "dpl", FTS_DPL, CM_INV },
1490 #endif /* FTP_SECURITY */
1491 { "error-action", FTS_ERR, 0 },
1492 { "filenames", FTS_CNV, 0 },
1493 { "get-filetype-switching", FTS_GFT, 0 },
1494 { "passive-mode", FTS_PSV, 0 },
1495 { "pasv", FTS_PSV, CM_INV },
1496 { "permissions", FTS_PRM, 0 },
1497 { "progress-messages", FTS_TST, 0 },
1498 { "send-port-commands", FTS_SPC, 0 },
1499 #ifndef NOCSETS
1500 { "server-character-set", FTS_CSR, 0 },
1501 #endif /* NOCSETS */
1502 { "server-time-offset", FTS_STO, 0 },
1503 #ifdef FTP_SRP
1504 { "srp", FTS_SRP, 0 },
1505 #else
1506 { "srp", FTS_SRP, CM_INV },
1507 #endif /* FTP_SRP */
1508 #ifdef FTP_TIMEOUT
1509 { "timeout", FTS_TMO, 0 },
1510 #endif /* FTP_TIMEOUT */
1511 { "type", FTS_TYP, 0 },
1512 { "unique-server-names", FTS_USN, 0 },
1513 { "verbose-mode", FTS_VBM, 0 },
1514 { "", 0, 0 }
1515 };
1516 static int nftpset = (sizeof(ftpset) / sizeof(struct keytab)) - 1;
1517
1518 /*
1519 GET and PUT switches are approximately the same as Kermit GET and SEND,
1520 and use the same SND_xxx definitions, but hijack a couple for FTP use.
1521 Don't just make up new ones, since the number of SND_xxx options must be
1522 known in advance for the switch-parsing arrays.
1523 */
1524 #define SND_USN SND_PRO /* /UNIQUE instead of /PROTOCOL */
1525 #define SND_PRM SND_PIP /* /PERMISSIONS instead of /PIPES */
1526 #define SND_TEN SND_CAL /* /TENEX instead of /CALIBRATE */
1527
1528 static struct keytab putswi[] = { /* FTP PUT switch table */
1529 { "/after", SND_AFT, CM_ARG },
1530 #ifdef PUTARRAY
1531 { "/array", SND_ARR, CM_ARG },
1532 #endif /* PUTARRAY */
1533 { "/as", SND_ASN, CM_ARG|CM_INV|CM_ABR },
1534 { "/as-name", SND_ASN, CM_ARG },
1535 { "/ascii", SND_TXT, CM_INV },
1536 { "/b", SND_BIN, CM_INV|CM_ABR },
1537 { "/before", SND_BEF, CM_ARG },
1538 { "/binary", SND_BIN, 0 },
1539 #ifdef PUTPIPE
1540 { "/command", SND_CMD, CM_PSH },
1541 #endif /* PUTPIPE */
1542 #ifdef COMMENT
1543 /* This works but it's dangerous */
1544 #ifdef DOUPDATE
1545 { "/dates-differ", SND_DIF, CM_INV },
1546 #endif /* DOUPDATE */
1547 #endif /* COMMENT */
1548 { "/delete", SND_DEL, 0 },
1549 #ifdef UNIXOROSK
1550 { "/dotfiles", SND_DOT, 0 },
1551 #endif /* UNIXOROSK */
1552 { "/error-action", SND_ERR, CM_ARG },
1553 { "/except", SND_EXC, CM_ARG },
1554 { "/filenames", SND_NAM, CM_ARG },
1555 #ifdef PIPESEND
1556 #ifndef NOSPL
1557 { "/filter", SND_FLT, CM_ARG|CM_PSH },
1558 #endif /* NOSPL */
1559 #endif /* PIPESEND */
1560 #ifdef CKSYMLINK
1561 { "/followlinks", SND_LNK, 0 },
1562 #endif /* CKSYMLINK */
1563 #ifdef VMS
1564 { "/image", SND_IMG, 0 },
1565 #else
1566 { "/image", SND_BIN, CM_INV },
1567 #endif /* VMS */
1568 { "/larger-than", SND_LAR, CM_ARG },
1569 { "/listfile", SND_FIL, CM_ARG },
1570 #ifndef NOCSETS
1571 { "/local-character-set", SND_CSL, CM_ARG },
1572 #endif /* NOCSETS */
1573 #ifdef CK_TMPDIR
1574 { "/move-to", SND_MOV, CM_ARG },
1575 #endif /* CK_TMPDIR */
1576 { "/nobackupfiles", SND_NOB, 0 },
1577 #ifdef UNIXOROSK
1578 { "/nodotfiles", SND_NOD, 0 },
1579 #endif /* UNIXOROSK */
1580 #ifdef CKSYMLINK
1581 { "/nofollowlinks", SND_NLK, 0 },
1582 #endif /* CKSYMLINK */
1583
1584 { "/not-after", SND_NAF, CM_ARG },
1585 { "/not-before", SND_NBE, CM_ARG },
1586 #ifdef UNIX
1587 { "/permissions", SND_PRM, CM_ARG },
1588 #else
1589 { "/permissions", SND_PRM, CM_ARG|CM_INV },
1590 #endif /* UNIX */
1591 { "/quiet", SND_SHH, 0 },
1592 #ifdef FTP_RESTART
1593 { "/recover", SND_RES, 0 },
1594 #endif /* FTP_RESTART */
1595 #ifdef RECURSIVE
1596 { "/recursive", SND_REC, 0 },
1597 #endif /* RECURSIVE */
1598 { "/rename-to", SND_REN, CM_ARG },
1599 #ifdef FTP_RESTART
1600 { "/restart", SND_RES, CM_INV },
1601 #endif /* FTP_RESTART */
1602 #ifndef NOCSETS
1603 { "/server-character-set", SND_CSR, CM_ARG },
1604 #endif /* NOCSETS */
1605 { "/server-rename-to", SND_SRN, CM_ARG },
1606 { "/simulate", SND_SIM, 0 },
1607 { "/since", SND_AFT, CM_INV|CM_ARG },
1608 { "/smaller-than", SND_SMA, CM_ARG },
1609 #ifdef COMMENT
1610 { "/starting-at", SND_STA, CM_ARG },
1611 #endif /* COMMENT */
1612 #ifdef RECURSIVE
1613 { "/subdirectories", SND_REC, CM_INV },
1614 #endif /* RECURSIVE */
1615 { "/tenex", SND_TEN, 0 },
1616 { "/text", SND_TXT, 0 },
1617 #ifndef NOCSETS
1618 { "/transparent", SND_XPA, 0 },
1619 #endif /* NOCSETS */
1620 { "/type", SND_TYP, CM_ARG },
1621 #ifdef DOUPDATE
1622 { "/update", SND_UPD, 0 },
1623 #endif /* DOUPDATE */
1624 { "/unique-server-names", SND_USN, 0 },
1625 { "", 0, 0 }
1626 };
1627 static int nputswi = (sizeof(putswi) / sizeof(struct keytab)) - 1;
1628
1629 static struct keytab getswi[] = { /* FTP [M]GET switch table */
1630 { "/after", SND_AFT, CM_INV },
1631 { "/as", SND_ASN, CM_ARG|CM_INV|CM_ABR },
1632 { "/as-name", SND_ASN, CM_ARG },
1633 { "/ascii", SND_TXT, CM_INV },
1634 { "/before", SND_BEF, CM_INV },
1635 { "/binary", SND_BIN, 0 },
1636 { "/collision", SND_COL, CM_ARG },
1637 #ifdef PUTPIPE
1638 { "/command", SND_CMD, CM_PSH },
1639 #endif /* PUTPIPE */
1640 { "/delete", SND_DEL, 0 },
1641 { "/error-action", SND_ERR, CM_ARG },
1642 { "/except", SND_EXC, CM_ARG },
1643 { "/filenames", SND_NAM, CM_ARG },
1644 #ifdef PIPESEND
1645 #ifndef NOSPL
1646 { "/filter", SND_FLT, CM_ARG|CM_PSH },
1647 #endif /* NOSPL */
1648 #endif /* PIPESEND */
1649 #ifdef VMS
1650 { "/image", SND_IMG, 0 },
1651 #else
1652 { "/image", SND_BIN, CM_INV },
1653 #endif /* VMS */
1654 { "/larger-than", SND_LAR, CM_ARG },
1655 { "/listfile", SND_FIL, CM_ARG },
1656 #ifndef NOCSETS
1657 { "/local-character-set", SND_CSL, CM_ARG },
1658 #endif /* NOCSETS */
1659 { "/match", SND_PAT, CM_ARG },
1660 { "/ml", SND_MLS, CM_INV|CM_ABR },
1661 { "/mls", SND_MLS, CM_INV|CM_ABR },
1662 { "/mlsd", SND_MLS, 0 },
1663 { "/mlst", SND_MLS, CM_INV },
1664 #ifdef CK_TMPDIR
1665 { "/move-to", SND_MOV, CM_ARG },
1666 #endif /* CK_TMPDIR */
1667 { "/namelist", SND_NML, CM_ARG },
1668 { "/nlst", SND_NLS, 0 },
1669 { "/nobackupfiles", SND_NOB, 0 },
1670 { "/nodotfiles", SND_NOD, 0 },
1671 #ifdef DOUPDATE
1672 { "/dates-differ", SND_DIF, CM_INV },
1673 #endif /* DOUPDATE */
1674 { "/not-after", SND_NAF, CM_INV },
1675 { "/not-before", SND_NBE, CM_INV },
1676 { "/permissions", SND_PRM, CM_INV },
1677 { "/quiet", SND_SHH, 0 },
1678 #ifdef FTP_RESTART
1679 { "/recover", SND_RES, 0 },
1680 #endif /* FTP_RESTART */
1681 #ifdef RECURSIVE
1682 { "/recursive", SND_REC, 0 },
1683 #endif /* RECURSIVE */
1684 { "/rename-to", SND_REN, CM_ARG },
1685 #ifdef FTP_RESTART
1686 { "/restart", SND_RES, CM_INV },
1687 #endif /* FTP_RESTART */
1688 #ifndef NOCSETS
1689 { "/server-character-set", SND_CSR, CM_ARG },
1690 #endif /* NOCSETS */
1691 { "/server-rename-to", SND_SRN, CM_ARG },
1692 { "/smaller-than", SND_SMA, CM_ARG },
1693 #ifdef RECURSIVE
1694 { "/subdirectories", SND_REC, CM_INV },
1695 #endif /* RECURSIVE */
1696 { "/text", SND_TXT, 0 },
1697 { "/tenex", SND_TEN, 0 },
1698 #ifndef NOCSETS
1699 { "/transparent", SND_XPA, 0 },
1700 #endif /* NOCSETS */
1701 { "/to-screen", SND_MAI, 0 },
1702 #ifdef DOUPDATE
1703 { "/update", SND_UPD, CM_INV },
1704 #endif /* DOUPDATE */
1705 { "", 0, 0 }
1706 };
1707 static int ngetswi = (sizeof(getswi) / sizeof(struct keytab)) - 1;
1708
1709 static struct keytab delswi[] = { /* FTP [M]DELETE switch table */
1710 { "/error-action", SND_ERR, CM_ARG },
1711 { "/except", SND_EXC, CM_ARG },
1712 { "/filenames", SND_NAM, CM_ARG },
1713 { "/larger-than", SND_LAR, CM_ARG },
1714 { "/nobackupfiles", SND_NOB, 0 },
1715 #ifdef UNIXOROSK
1716 { "/nodotfiles", SND_NOD, 0 },
1717 #endif /* UNIXOROSK */
1718 { "/quiet", SND_SHH, 0 },
1719 #ifdef RECURSIVE
1720 { "/recursive", SND_REC, 0 },
1721 #endif /* RECURSIVE */
1722 { "/smaller-than", SND_SMA, CM_ARG },
1723 #ifdef RECURSIVE
1724 { "/subdirectories", SND_REC, CM_INV },
1725 #endif /* RECURSIVE */
1726 { "", 0, 0 }
1727 };
1728 static int ndelswi = (sizeof(delswi) / sizeof(struct keytab)) - 1;
1729
1730 static struct keytab fntab[] = { /* Filename conversion keyword table */
1731 { "automatic", 2, CNV_AUTO },
1732 { "converted", 1, CNV_CNV },
1733 { "literal", 0, CNV_LIT }
1734 };
1735 static int nfntab = (sizeof(fntab) / sizeof(struct keytab));
1736
1737 static struct keytab ftptyp[] = { /* SET FTP TYPE table */
1738 { "ascii", FTT_ASC, 0 },
1739 { "binary", FTT_BIN, 0 },
1740 { "tenex", FTT_TEN, 0 },
1741 { "text", FTT_ASC, CM_INV },
1742 { "", 0, 0 }
1743 };
1744 static int nftptyp = (sizeof(ftptyp) / sizeof(struct keytab)) - 1;
1745
1746 #ifdef FTP_SECURITY
1747 static struct keytab ftppro[] = { /* SET FTP PROTECTION-LEVEL table */
1748 { "clear", FPL_CLR, 0 },
1749 { "confidential", FPL_CON, 0 },
1750 { "private", FPL_PRV, 0 },
1751 { "safe", FPL_SAF, 0 },
1752 { "", 0, 0 }
1753 };
1754 static int nftppro = (sizeof(ftppro) / sizeof(struct keytab)) - 1;
1755 #endif /* FTP_SECURITY */
1756
1757 /* Definitions for FTP from RFC765. */
1758
1759 /* Reply codes */
1760
1761 #define REPLY_PRELIM 1 /* Positive preliminary */
1762 #define REPLY_COMPLETE 2 /* Positive completion */
1763 #define REPLY_CONTINUE 3 /* Positive intermediate */
1764 #define REPLY_TRANSIENT 4 /* Transient negative completion */
1765 #define REPLY_ERROR 5 /* Permanent negative completion */
1766 #define REPLY_SECURE 6 /* Security encoded message */
1767
1768 /* Form codes and names */
1769
1770 #define FORM_N 1 /* Non-print */
1771 #define FORM_T 2 /* Telnet format effectors */
1772 #define FORM_C 3 /* Carriage control (ASA) */
1773
1774 /* Structure codes and names */
1775
1776 #define STRU_F 1 /* File (no record structure) */
1777 #define STRU_R 2 /* Record structure */
1778 #define STRU_P 3 /* Page structure */
1779
1780 /* Mode types and names */
1781
1782 #define MODE_S 1 /* Stream */
1783 #define MODE_B 2 /* Block */
1784 #define MODE_C 3 /* Compressed */
1785
1786 /* Protection levels and names */
1787
1788 #define PROT_C 1 /* Clear */
1789 #define PROT_S 2 /* Safe */
1790 #define PROT_P 3 /* Private */
1791 #define PROT_E 4 /* Confidential */
1792
1793 #ifdef COMMENT /* Not used */
1794 #ifdef FTP_NAMES
1795 char *strunames[] = {"0", "File", "Record", "Page" };
1796 char *formnames[] = {"0", "Nonprint", "Telnet", "Carriage-control" };
1797 char *modenames[] = {"0", "Stream", "Block", "Compressed" };
1798 char *levelnames[] = {"0", "Clear", "Safe", "Private", "Confidential" };
1799 #endif /* FTP_NAMES */
1800
1801 /* Record Tokens */
1802
1803 #define REC_ESC '\377' /* Record-mode Escape */
1804 #define REC_EOR '\001' /* Record-mode End-of-Record */
1805 #define REC_EOF '\002' /* Record-mode End-of-File */
1806
1807 /* Block Header */
1808
1809 #define BLK_EOR 0x80 /* Block is End-of-Record */
1810 #define BLK_EOF 0x40 /* Block is End-of-File */
1811 #define BLK_REPLY_ERRORS 0x20 /* Block might have errors */
1812 #define BLK_RESTART 0x10 /* Block is Restart Marker */
1813 #define BLK_BYTECOUNT 2 /* Bytes in this block */
1814 #endif /* COMMENT */
1815
1816 #define RADIX_ENCODE 0 /* radix_encode() function codes */
1817 #define RADIX_DECODE 1
1818
1819 /*
1820 The default setpbsz() value in the Unix FTP client is 1<<20 (1MB). This
1821 results in a serious performance degradation due to the increased number
1822 of page faults and the inability to overlap encrypt/decrypt, file i/o, and
1823 network i/o. So instead we set the value to 1<<13 (8K), about half the size
1824 of the typical TCP window. Maybe we should add a command to allow the value
1825 to be changed.
1826 */
1827 #define DEFAULT_PBSZ 1<<13
1828
1829 /* Prototypes */
1830
1831 _PROTOTYP(int remtxt, (char **) );
1832 _PROTOTYP(char * gskreason, (int) );
1833 _PROTOTYP(static int ftpclose,(void));
1834 _PROTOTYP(static int zzsend, (int, CHAR));
1835 _PROTOTYP(static int getreply,(int,int,int,int,int));
1836 _PROTOTYP(static int radix_encode,(CHAR[], CHAR[], int, int *, int));
1837 _PROTOTYP(static int setpbsz,(unsigned int));
1838 _PROTOTYP(static int recvrequest,(char *,char *,char *,char *,
1839 int,int,char *,int,int,int));
1840 _PROTOTYP(static int ftpcmd,(char *,char *,int,int,int));
1841 _PROTOTYP(static int fts_cpl,(int));
1842 _PROTOTYP(static int fts_dpl,(int));
1843 #ifdef FTP_SECURITY
1844 _PROTOTYP(static int ftp_auth, (void));
1845 #endif /* FTP_SECURITY */
1846 _PROTOTYP(static int ftp_user, (char *, char *, char *));
1847 _PROTOTYP(static int ftp_login, (char *));
1848 _PROTOTYP(static int ftp_reset, (void));
1849 _PROTOTYP(static int ftp_rename, (char *, char *));
1850 _PROTOTYP(static int ftp_umask, (char *));
1851 _PROTOTYP(static int secure_flush, (int));
1852 #ifdef COMMENT
1853 _PROTOTYP(static int secure_putc, (char, int));
1854 #endif /* COMMENT */
1855 _PROTOTYP(static int secure_write, (int, CHAR *, unsigned int));
1856 _PROTOTYP(static int scommand, (char *));
1857 _PROTOTYP(static int secure_putbuf, (int, CHAR *, unsigned int));
1858 _PROTOTYP(static int secure_getc, (int, int));
1859 _PROTOTYP(static int secure_getbyte, (int, int));
1860 _PROTOTYP(static int secure_read, (int, char *, int));
1861 _PROTOTYP(static int initconn, (void));
1862 _PROTOTYP(static int dataconn, (char *));
1863 _PROTOTYP(static int setprotbuf,(unsigned int));
1864 _PROTOTYP(static int sendrequest, (char *, char *, char *, int,int,int,int));
1865
1866 _PROTOTYP(static char * radix_error,(int));
1867 _PROTOTYP(static char * ftp_hookup,(char *, int, int));
1868 _PROTOTYP(static CHAR * remote_files, (int, CHAR *, CHAR *, int));
1869
1870 _PROTOTYP(static VOID mlsreset, (void));
1871 _PROTOTYP(static VOID secure_error, (char *fmt, ...));
1872 _PROTOTYP(static VOID lostpeer, (void));
1873 _PROTOTYP(static VOID cancel_remote, (int));
1874 _PROTOTYP(static VOID changetype, (int, int));
1875
1876 _PROTOTYP(static sigtype cmdcancel, (int));
1877
1878 #ifdef FTP_SRP
1879 _PROTOTYP(static int srp_reset, ());
1880 _PROTOTYP(static int srp_ftp_auth, (char *,char *,char *));
1881 _PROTOTYP(static int srp_put, (CHAR *, CHAR **, int, int *));
1882 _PROTOTYP(static int srp_get, (CHAR **, CHAR **, int *, int *));
1883 _PROTOTYP(static int srp_encode, (int, CHAR *, CHAR *, unsigned int));
1884 _PROTOTYP(static int srp_decode, (int, CHAR *, CHAR *, unsigned int));
1885 _PROTOTYP(static int srp_selcipher, (char *));
1886 _PROTOTYP(static int srp_selhash, (char *));
1887 #endif /* FTP_SRP */
1888
1889 #ifdef FTP_GSSAPI
1890 _PROTOTYP(static void user_gss_error,(OM_uint32, OM_uint32,char *));
1891 #endif /* FTP_GSSAPI */
1892
1893 /* D O F T P A R G -- Do an FTP command-line argument. */
1894
1895 #ifdef FTP_SECURITY
1896 #ifndef NOICP
1897 #define FT_NOGSS 1
1898 #define FT_NOK4 2
1899 #define FT_NOSRP 3
1900 #define FT_NOSSL 4
1901 #define FT_NOTLS 5
1902 #define FT_CERTFI 6
1903 #define FT_OKCERT 7
1904 #define FT_DEBUG 8
1905 #define FT_KEY 9
1906 #define FT_SECURE 10
1907 #define FT_VERIFY 11
1908
1909 static struct keytab ftpztab[] = {
1910 { "!gss", FT_NOGSS, 0 },
1911 { "!krb4", FT_NOK4, 0 },
1912 { "!srp", FT_NOSRP, 0 },
1913 { "!ssl", FT_NOSSL, 0 },
1914 { "!tls", FT_NOTLS, 0 },
1915 { "cert", FT_CERTFI, CM_ARG },
1916 { "certsok", FT_OKCERT, 0 },
1917 { "debug", FT_DEBUG, 0 },
1918 { "key", FT_KEY, CM_ARG },
1919 { "nogss", FT_NOGSS, 0 },
1920 { "nokrb4", FT_NOK4, 0 },
1921 { "nosrp", FT_NOSRP, 0 },
1922 { "nossl", FT_NOSSL, 0 },
1923 { "notls", FT_NOTLS, 0 },
1924 #ifdef COMMENT
1925 { "secure", FT_SECURE, 0 },
1926 #endif /* COMMENT */
1927 { "verify", FT_VERIFY, CM_ARG },
1928 { "", 0, 0 }
1929 };
1930 static int nftpztab = sizeof(ftpztab) / sizeof(struct keytab) - 1;
1931
1932 /*
1933 The following cipher and hash tables should be replaced with
1934 dynamicly created versions based upon the linked library.
1935 */
1936 #define SRP_BLOWFISH_ECB 1
1937 #define SRP_BLOWFISH_CBC 2
1938 #define SRP_BLOWFISH_CFB64 3
1939 #define SRP_BLOWFISH_OFB64 4
1940 #define SRP_CAST5_ECB 5
1941 #define SRP_CAST5_CBC 6
1942 #define SRP_CAST5_CFB64 7
1943 #define SRP_CAST5_OFB64 8
1944 #define SRP_DES_ECB 9
1945 #define SRP_DES_CBC 10
1946 #define SRP_DES_CFB64 11
1947 #define SRP_DES_OFB64 12
1948 #define SRP_DES3_ECB 13
1949 #define SRP_DES3_CBC 14
1950 #define SRP_DES3_CFB64 15
1951 #define SRP_DES3_OFB64 16
1952
1953 static struct keytab ciphertab[] = {
1954 { "blowfish_ecb", SRP_BLOWFISH_ECB, 0 },
1955 { "blowfish_cbc", SRP_BLOWFISH_CBC, 0 },
1956 { "blowfish_cfb64", SRP_BLOWFISH_CFB64, 0 },
1957 { "blowfish_ofb64", SRP_BLOWFISH_OFB64, 0 },
1958 { "cast5_ecb", SRP_CAST5_ECB, 0 },
1959 { "cast5_cbc", SRP_CAST5_CBC, 0 },
1960 { "cast5_cfb64", SRP_CAST5_CFB64, 0 },
1961 { "cast5_ofb64", SRP_CAST5_OFB64, 0 },
1962 { "des_ecb", SRP_DES_ECB, 0 },
1963 { "des_cbc", SRP_DES_CBC, 0 },
1964 { "des_cfb64", SRP_DES_CFB64, 0 },
1965 { "des_ofb64", SRP_DES_OFB64, 0 },
1966 { "des3_ecb", SRP_DES3_ECB, 0 },
1967 { "des3_cbc", SRP_DES3_CBC, 0 },
1968 { "des3_cfb64", SRP_DES3_CFB64, 0 },
1969 { "des3_ofb64", SRP_DES3_OFB64, 0 },
1970 { "none", 0, 0 },
1971 { "", 0, 0 }
1972 };
1973 static int nciphertab = sizeof(ciphertab) / sizeof(struct keytab) - 1;
1974
1975 #define SRP_MD5 1
1976 #define SRP_SHA 2
1977 static struct keytab hashtab[] = {
1978 { "md5", SRP_MD5, 0 },
1979 { "none", 0, 0 },
1980 { "sha", SRP_SHA, 0 },
1981 { "", 0, 0 }
1982 };
1983 static int nhashtab = sizeof(hashtab) / sizeof(struct keytab) - 1;
1984 #endif /* NOICP */
1985 #endif /* FTP_SECURITY */
1986
1987 static char *
strval(s1,s2)1988 strval(s1,s2) char * s1, * s2; {
1989 if (!s1) s1 = "";
1990 if (!s2) s2 = "";
1991 return(*s1 ? s1 : (*s2 ? s2 : "(none)"));
1992 }
1993
1994 #ifndef NOCSETS
1995 static char * rfnptr = NULL;
1996 static int rfnlen = 0;
1997 static char rfnbuf[RFNBUFSIZ]; /* Remote filename translate buffer */
1998 static char * xgnbp = NULL;
1999
2000 static int
strgetc()2001 strgetc() { /* Helper function for xgnbyte() */
2002 int c;
2003 if (!xgnbp)
2004 return(-1);
2005 if (!*xgnbp)
2006 return(-1);
2007 c = (unsigned) *xgnbp++;
2008 return(((unsigned) c) & 0xff);
2009 }
2010
2011 static int /* Helper function for xpnbyte() */
2012 #ifdef CK_ANSIC
strputc(char c)2013 strputc(char c)
2014 #else
2015 strputc(c) char c;
2016 #endif /* CK_ANSIC */
2017 {
2018 rfnlen = rfnptr - rfnbuf;
2019 if (rfnlen >= (RFNBUFSIZ - 1))
2020 return(-1);
2021 *rfnptr++ = c;
2022 *rfnptr = NUL;
2023 return(0);
2024 }
2025
2026 static int
2027 #ifdef CK_ANSIC
xprintc(char c)2028 xprintc(char c)
2029 #else
2030 xprintc(c) char c;
2031 #endif /* CK_ANSIC */
2032 {
2033 printf("%c",c);
2034 return(0);
2035 }
2036
2037 static VOID
bytswap(c0,c1)2038 bytswap(c0,c1) int * c0, * c1; {
2039 int t;
2040 t = *c0;
2041 *c0 = *c1;
2042 *c1 = t;
2043 }
2044 #endif /* NOCSETS */
2045
2046 #ifdef CKLOGDIAL
2047 char ftplogbuf[CXLOGBUFL] = { NUL, NUL }; /* Connection Log */
2048 int ftplogactive = 0;
2049 long ftplogprev = 0L;
2050
2051 VOID
ftplogend()2052 ftplogend() {
2053 extern int dialog;
2054 extern char diafil[];
2055 long d1, d2, t1, t2;
2056 char buf[32], * p;
2057
2058 debug(F111,"ftp cx log active",ckitoa(dialog),ftplogactive);
2059 debug(F110,"ftp cx log buf",ftplogbuf,0);
2060
2061 if (!ftplogactive || !ftplogbuf[0]) /* No active record */
2062 return;
2063
2064 ftplogactive = 0; /* Record is not active */
2065
2066 d1 = mjd((char *)ftplogbuf); /* Get start date of this session */
2067 ckstrncpy(buf,ckdate(),31); /* Get current date */
2068 d2 = mjd(buf); /* Convert them to mjds */
2069 p = ftplogbuf; /* Get start time */
2070 p[11] = NUL;
2071 p[14] = NUL; /* Convert to seconds */
2072 t1 = atol(p+9) * 3600L + atol(p+12) * 60L + atol(p+15);
2073 p[11] = ':';
2074 p[14] = ':';
2075 p = buf; /* Get end time */
2076 p[11] = NUL;
2077 p[14] = NUL;
2078 t2 = atol(p+9) * 3600L + atol(p+12) * 60L + atol(p+15);
2079 t2 = ((d2 - d1) * 86400L) + (t2 - t1); /* Compute elapsed time */
2080 if (t2 > -1L) {
2081 ftplogprev = t2;
2082 p = hhmmss(t2);
2083 ckstrncat(ftplogbuf,"E=",CXLOGBUFL); /* Append to log record */
2084 ckstrncat(ftplogbuf,p,CXLOGBUFL);
2085 } else
2086 ftplogprev = 0L;
2087 debug(F101,"ftp cx log dialog","",dialog);
2088 if (dialog) { /* If logging */
2089 int x;
2090 x = diaopn(diafil,1,1); /* Open log in append mode */
2091 if (x > 0) {
2092 debug(F101,"ftp cx log open","",x);
2093 x = zsoutl(ZDIFIL,ftplogbuf); /* Write the record */
2094 debug(F101,"ftp cx log write","",x);
2095 x = zclose(ZDIFIL); /* Close the log */
2096 debug(F101,"ftp cx log close","",x);
2097 }
2098 }
2099 }
2100
2101 VOID
dologftp()2102 dologftp() {
2103 ftplogend(); /* Previous session not closed out? */
2104 ftplogprev = 0L;
2105 ftplogactive = 1; /* Record is active */
2106
2107 ckmakxmsg(ftplogbuf,CXLOGBUFL,
2108 ckdate()," ",strval(ftp_logname,NULL)," ",ckgetpid(),
2109 " T=FTP N=", strval(ftp_host,NULL)," H=",myhost,
2110 " P=", ckitoa(ftp_port)," "); /* SMS 2007/02/15 */
2111 debug(F110,"ftp cx log begin",ftplogbuf,0);
2112 }
2113 #endif /* CKLOGDIAL */
2114
2115 static char * dummy[2] = { NULL, NULL };
2116
2117 static struct keytab modetab[] = {
2118 { "active", 0, 0 },
2119 { "passive", 1, 0 }
2120 };
2121
2122 #ifndef NOCMDL
2123 int /* Called from ckuusy.c */
2124 #ifdef CK_ANSIC
doftparg(char c)2125 doftparg(char c)
2126 #else
2127 doftparg(c) char c;
2128 #endif /* CK_ANSIC */
2129 /* doftparg */ {
2130 int x, z;
2131 char *xp;
2132 extern char **xargv, *xarg0;
2133 extern int xargc, stayflg, haveftpuid;
2134 extern char uidbuf[];
2135
2136 xp = *xargv+1; /* Pointer for bundled args */
2137 while (c) {
2138 if (ckstrchr("MuDPkcHzm",c)) { /* Options that take arguments */
2139 if (*(xp+1)) {
2140 fatal("?Invalid argument bundling");
2141 }
2142 xargv++, xargc--;
2143 if ((xargc < 1) || (**xargv == '-')) {
2144 fatal("?Required argument missing");
2145 }
2146 }
2147 switch (c) { /* Big switch on arg */
2148 case 'h': /* help */
2149 printf("C-Kermit's FTP client command-line personality. Usage:\n");
2150 printf(" %s [ options ] host [ port ] [-pg files ]\n\n",xarg0);
2151 printf("Options:\n");
2152 printf(" -h = help (this message)\n");
2153 printf(" -m mode = \"passive\" (default) or \"active\"\n");
2154 printf(" -u name = username for autologin (or -M)\n");
2155 printf(" -P password = password for autologin (RISKY)\n");
2156 printf(" -A = autologin anonymously\n");
2157 printf(" -D directory = cd after autologin\n");
2158 printf(" -b = force binary mode\n");
2159 printf(" -a = force text (\"ascii\") mode (or -T)\n");
2160 printf(" -d = debug (double to add timestamps)\n");
2161 printf(" -n = no autologin\n");
2162 printf(" -v = verbose (default)\n");
2163 printf(" -q = quiet\n");
2164 printf(" -S = Stay (issue command prompt when done)\n");
2165 printf(" -Y = do not execute Kermit init file\n");
2166 printf(" -p files = files to put after autologin (or -s)\n");
2167 printf(" -g files = files to get after autologin\n");
2168 printf(" -R = recursive (for use with -p)\n");
2169
2170 #ifdef FTP_SECURITY
2171 printf("\nSecurity options:\n");
2172 printf(" -k realm = Kerberos 4 realm\n");
2173 printf(" -f = Kerboros 5 credentials forwarding\n");
2174 printf(" -x = autoencryption mode\n");
2175 printf(" -c cipher = SRP cipher type\n");
2176 printf(" -H hash = SRP encryption hash\n");
2177 printf(" -z option = Security options\n");
2178 #endif /* FTP_SECURITY */
2179
2180 printf("\n-p or -g, if given, should be last. Example:\n");
2181 printf(" ftp -A kermit.columbia.edu -D kermit -ag TESTFILE\n");
2182
2183 doexit(GOOD_EXIT,-1);
2184 break;
2185
2186 case 'R': /* Recursive */
2187 recursive = 1;
2188 break;
2189
2190 case 'd': /* Debug */
2191 #ifdef DEBUG
2192 if (deblog) {
2193 extern int debtim;
2194 debtim = 1;
2195 } else {
2196 deblog = debopn("debug.log",0);
2197 debok = 1;
2198 }
2199 #endif /* DEBUG */
2200 /* fall thru on purpose */
2201
2202 case 't': /* Trace */
2203 ftp_deb++;
2204 break;
2205
2206 case 'n': /* No autologin */
2207 ftp_log = 0;
2208 break;
2209
2210 case 'i': /* No prompt */
2211 case 'v': /* Verbose */
2212 break; /* (ignored) */
2213
2214 case 'q': /* Quiet */
2215 quiet = 1;
2216 break;
2217
2218 case 'S': /* Stay */
2219 stayflg = 1;
2220 break;
2221
2222 case 'M':
2223 case 'u': /* My User Name */
2224 if ((int)strlen(*xargv) > 63) {
2225 fatal("username too long");
2226 }
2227 ckstrncpy(uidbuf,*xargv,UIDBUFLEN);
2228 haveftpuid = 1;
2229 break;
2230
2231 case 'A':
2232 ckstrncpy(uidbuf,"anonymous",UIDBUFLEN);
2233 haveftpuid = 1;
2234 break;
2235
2236 case 'T': /* Text */
2237 case 'a': /* "ascii" */
2238 case 'b': /* Binary */
2239 binary = (c == 'b') ? FTT_BIN : FTT_ASC;
2240 ftp_xfermode = XMODE_M;
2241 filepeek = 0;
2242 patterns = 0;
2243 break;
2244
2245 case 'g': /* Get */
2246 case 'p': /* Put */
2247 case 's': { /* Send (= Put) */
2248 int havefiles, rc;
2249 if (ftp_action) {
2250 fatal("Only one FTP action at a time please");
2251 }
2252 if (*(xp+1)) {
2253 fatal("invalid argument bundling after -s");
2254 }
2255 nfils = 0; /* Initialize file counter */
2256 havefiles = 0; /* Assume nothing to send */
2257 cmlist = xargv + 1; /* Remember this pointer */
2258
2259 while (++xargv, --xargc > 0) { /* Traverse the list */
2260 if (c == 'g') {
2261 havefiles++;
2262 nfils++;
2263 continue;
2264 }
2265 #ifdef RECURSIVE
2266 if (!strcmp(*xargv,".")) {
2267 havefiles = 1;
2268 nfils++;
2269 recursive = 1;
2270 } else
2271 #endif /* RECURSIVE */
2272 if ((rc = zchki(*xargv)) > -1 || (rc == -2)) {
2273 if (rc != -2)
2274 havefiles = 1;
2275 nfils++;
2276 } else if (iswild(*xargv) && nzxpand(*xargv,0) > 0) {
2277 havefiles = 1;
2278 nfils++;
2279 }
2280 }
2281 xargc++, xargv--; /* Adjust argv/argc */
2282 if (!havefiles) {
2283 if (c == 'g') {
2284 fatal("No files to put");
2285 } else {
2286 fatal("No files to get");
2287 }
2288 }
2289 ftp_action = c;
2290 break;
2291 }
2292 case 'D': /* Directory */
2293 makestr(&ftp_rdir,*xargv);
2294 break;
2295
2296 case 'm': /* Mode (Active/Passive */
2297 ftp_psv = lookup(modetab,*xargv,2,NULL);
2298 if (ftp_psv < 0) fatal("Invalid mode");
2299 break;
2300
2301 case 'P':
2302 makestr(&ftp_tmp,*xargv); /* You-Know-What */
2303 break;
2304
2305 case 'Y': /* No initialization file */
2306 break; /* (already done in prescan) */
2307
2308 #ifdef CK_URL
2309 case 'U': { /* URL */
2310 /* These are set by urlparse() - any not set are NULL */
2311 if (g_url.hos) {
2312 /*
2313 Kermit has accepted host:port notation since many years before URLs were
2314 invented. Unfortunately, URLs conflict with this notation. Thus "ftp
2315 host:449" looks like a URL and results in service = host and host = 449.
2316 Here we try to catch this situation transparently to the user.
2317 */
2318 if (ckstrcmp(g_url.svc,"ftp",-1,0)
2319 #ifdef CK_SSL
2320 && ckstrcmp(g_url.svc,"ftps",-1,0)
2321 #endif /* CK_SSL */
2322 ) {
2323 if (!g_url.usr &&
2324 !g_url.psw &&
2325 !g_url.por &&
2326 !g_url.pth) {
2327 g_url.por = g_url.hos;
2328 g_url.hos = g_url.svc;
2329 g_url.svc = "ftp";
2330 } else {
2331 ckmakmsg(tmpbuf,TMPBUFSIZ,"Non-FTP URL: service=",
2332 g_url.svc," host=",g_url.hos);
2333 fatal(tmpbuf);
2334 }
2335 }
2336 makestr(&ftp_host,g_url.hos);
2337 if (g_url.usr) {
2338 haveftpuid = 1;
2339 ckstrncpy(uidbuf,g_url.usr,UIDBUFLEN);
2340 makestr(&ftp_logname,uidbuf);
2341 }
2342 if (g_url.psw) {
2343 makestr(&ftp_tmp,g_url.psw);
2344 }
2345 if (g_url.pth) {
2346 if (!g_url.usr) {
2347 haveftpuid = 1;
2348 ckstrncpy(uidbuf,"anonymous",UIDBUFLEN);
2349 makestr(&ftp_logname,uidbuf);
2350 }
2351 if (ftp_action) {
2352 fatal("Only one FTP action at a time please");
2353 }
2354 if (!stayflg)
2355 quiet = 1;
2356 nfils = 1;
2357 dummy[0] = g_url.pth;
2358 cmlist = dummy;
2359 ftp_action = 'g';
2360 }
2361 xp = NULL;
2362 haveurl = 1;
2363 }
2364 break;
2365 }
2366 #endif /* CK_URL */
2367
2368 #ifdef FTP_SECURITY
2369 case 'k': { /* K4 Realm */
2370 #ifdef FTP_KRB4
2371 ckstrncpy(ftp_realm,*xargv, REALM_SZ);
2372 #endif /* FTP_KRB4 */
2373 if (ftp_deb) printf("K4 Realm = [%s]\n",*xargv);
2374 break;
2375 }
2376 case 'f': {
2377 #ifdef FTP_GSSAPI
2378 ftp_cfw = 1;
2379 if (ftp_deb) printf("K5 Credentials Forwarding\n");
2380 #else /* FTP_GSSAPI */
2381 printf("K5 Credentials Forwarding not supported\n");
2382 #endif /* FTP_GSSAPI */
2383 break;
2384 }
2385 case 'x': {
2386 ftp_cry = 1;
2387 if (ftp_deb) printf("Autoencryption\n");
2388 break;
2389 }
2390 case 'c': { /* Cipher */
2391 #ifdef FTP_SRP
2392 if (!srp_selcipher(*xargv)) {
2393 if (ftp_deb) printf("SRP cipher type: \"%s\"\n",*xargv);
2394 } else
2395 printf("?Invalid SRP cipher type: \"%s\"\n",*xargv);
2396 #else /* FTP_SRP */
2397 printf("?SRP not supported\n");
2398 #endif /* FTP_SRP */
2399 break;
2400 }
2401 case 'H': {
2402 #ifdef FTP_SRP
2403 if (!srp_selhash(*xargv)) {
2404 if (ftp_deb) printf("SRP hash type: \"%s\"\n",*xargv);
2405 } else
2406 printf("?Invalid SRP hash type: \"%s\"\n",*xargv);
2407 #else /* FTP_SRP */
2408 printf("?SRP not supported\n");
2409 #endif /* FTP_SRP */
2410 break;
2411 }
2412 case 'z': {
2413 /* *xargv contains a value of the form tag=value */
2414 /* we need to lookup the tag and save the value */
2415 char * p = NULL, * q = NULL;
2416 makestr(&p,*xargv);
2417 y = ckindex("=",p,0,0,1);
2418 if (y > 0)
2419 p[y-1] = '\0';
2420 x = lookup(ftpztab,p,nftpztab,&z);
2421 if (x < 0) {
2422 printf("?Invalid security option: \"%s\"\n",p);
2423 } else {
2424 if (ftp_deb)
2425 printf("Security option: \"%s",p);
2426 if (ftpztab[z].flgs & CM_ARG) {
2427 if (y <= 0)
2428 fatal("?Missing required value");
2429 q = &p[y];
2430 if (!*q)
2431 fatal("?Missing required value");
2432 if (ftp_deb)
2433 printf("=%s\"",q);
2434 }
2435 switch (ftpztab[z].kwval) { /* -z options w/args */
2436 case FT_NOGSS:
2437 #ifdef FTP_GSSAPI
2438 for (z = 0; z < FTPATYPS && ftp_auth_type[z]; z++) {
2439 if (ftp_auth_type[z] == FTA_GK5) {
2440 for (y = z;
2441 y < (FTPATYPS-1) && ftp_auth_type[y];
2442 y++
2443 )
2444 ftp_auth_type[y] = ftp_auth_type[y+1];
2445 ftp_auth_type[FTPATYPS-1] = 0;
2446 break;
2447 }
2448 }
2449 #endif /* FTP_GSSAPI */
2450 break;
2451 case FT_NOK4:
2452 #ifdef FTP_KRB4
2453 for (z = 0; z < FTPATYPS && ftp_auth_type[z]; z++) {
2454 if (ftp_auth_type[z] == FTA_K4) {
2455 for (y = z;
2456 y < (FTPATYPS-1) && ftp_auth_type[y];
2457 y++
2458 )
2459 ftp_auth_type[y] = ftp_auth_type[y+1];
2460 ftp_auth_type[FTPATYPS-1] = 0;
2461 break;
2462 }
2463 }
2464 #endif /* FTP_KRB4 */
2465 break;
2466 case FT_NOSRP:
2467 #ifdef FTP_SRP
2468 for (z = 0; z < FTPATYPS && ftp_auth_type[z]; z++) {
2469 if (ftp_auth_type[z] == FTA_SRP) {
2470 for (y = z;
2471 y < (FTPATYPS-1) && ftp_auth_type[y];
2472 y++
2473 )
2474 ftp_auth_type[y] = ftp_auth_type[y+1];
2475 ftp_auth_type[FTPATYPS-1] = 0;
2476 break;
2477 }
2478 }
2479 #endif /* FTP_SRP */
2480 break;
2481 case FT_NOSSL:
2482 #ifdef CK_SSL
2483 for (z = 0; z < FTPATYPS && ftp_auth_type[z]; z++) {
2484 if (ftp_auth_type[z] == FTA_SSL) {
2485 for (y = z;
2486 y < (FTPATYPS-1) && ftp_auth_type[y];
2487 y++
2488 )
2489 ftp_auth_type[y] = ftp_auth_type[y+1];
2490 ftp_auth_type[FTPATYPS-1] = 0;
2491 break;
2492 }
2493 }
2494 #endif /* CK_SSL */
2495 break;
2496 case FT_NOTLS:
2497 #ifdef CK_SSL
2498 for (z = 0; z < FTPATYPS && ftp_auth_type[z]; z++) {
2499 if (ftp_auth_type[z] == FTA_TLS) {
2500 for (y = z;
2501 y < (FTPATYPS-1) && ftp_auth_type[y];
2502 y++
2503 )
2504 ftp_auth_type[y] = ftp_auth_type[y+1];
2505 ftp_auth_type[FTPATYPS-1] = 0;
2506 break;
2507 }
2508 }
2509 #endif /* CK_SSL */
2510 break;
2511 case FT_CERTFI:
2512 #ifdef CK_SSL
2513 makestr(&ssl_rsa_cert_file,q);
2514 #endif /* CK_SSL */
2515 break;
2516 case FT_OKCERT:
2517 #ifdef CK_SSL
2518 ssl_certsok_flag = 1;
2519 #endif /* CK_SSL */
2520 break;
2521 case FT_DEBUG:
2522 #ifdef DEBUG
2523 if (deblog) {
2524 extern int debtim;
2525 debtim = 1;
2526 } else {
2527 deblog = debopn("debug.log",0);
2528 }
2529 #endif /* DEBUG */
2530 break;
2531 case FT_KEY:
2532 #ifdef CK_SSL
2533 makestr(&ssl_rsa_key_file,q);
2534 #endif /* CK_SSL */
2535 break;
2536 case FT_SECURE:
2537 /* no equivalent */
2538 break;
2539 case FT_VERIFY:
2540 #ifdef CK_SSL
2541 if (!rdigits(q))
2542 printf("?Bad number: %s\n",q);
2543 ssl_verify_flag = atoi(q);
2544 #endif /* CK_SSL */
2545 break;
2546 }
2547 }
2548 if (ftp_deb) printf("\"\n");
2549 free(p);
2550 break;
2551 }
2552 #endif /* FTP_SECURITY */
2553
2554 default:
2555 fatal2(*xargv,
2556 "unknown command-line option, type \"ftp -h\" for help"
2557 );
2558 }
2559 if (!xp) break;
2560 c = *++xp; /* See if options are bundled */
2561 }
2562 return(0);
2563 }
2564 #endif /* NOCMDL */
2565
2566 int
ftpisconnected()2567 ftpisconnected() {
2568 return(connected);
2569 }
2570
2571 int
ftpisloggedin()2572 ftpisloggedin() {
2573 return(connected ? loggedin : 0);
2574 }
2575
2576 int
ftpissecure()2577 ftpissecure() {
2578 return((ftp_dpl == FPL_CLR && !ssl_ftp_proxy) ? 0 : 1);
2579 }
2580
2581 static VOID
ftscreen(n,c,z,s)2582 ftscreen(n, c, z, s) int n; char c; CK_OFF_T z; char * s; {
2583 if (displa && fdispla && !backgrd && !quiet && !out2screen) {
2584 if (!dpyactive) {
2585 ckscreen(SCR_PT,'S',(CK_OFF_T)0,"");
2586 dpyactive = 1;
2587 }
2588 ckscreen(n,c,z,s);
2589 }
2590 }
2591
2592 #ifndef OS2
2593 /* g m s t i m e r -- Millisecond timer */
2594
2595 long
gmstimer()2596 gmstimer() {
2597 #ifdef HAVE_MSECS
2598 /* For those versions of ztime() that also set global ztmsec. */
2599 char *p = NULL;
2600 long z;
2601 ztime(&p);
2602 if (!p) return(0L);
2603 if (!*p) return(0L);
2604 z = atol(p+11) * 3600L + atol(p+14) * 60L + atol(p+17);
2605 return(z * 1000 + ztmsec);
2606 #else
2607 return((long)time(NULL) * 1000L);
2608 #endif /* HAVE_MSECS */
2609 }
2610 #endif /* OS2 */
2611
2612 /* d o s e t f t p -- The SET FTP command */
2613
2614 int
dosetftp()2615 dosetftp() {
2616 int cx;
2617 if ((cx = cmkey(ftpset,nftpset,"","",xxstring)) < 0) /* Set what? */
2618 return(cx);
2619 switch (cx) {
2620
2621 case FTS_FNC: /* Filename collision action */
2622 if ((x = cmkey(ftpcolxtab,nftpcolx,"","",xxstring)) < 0)
2623 return(x);
2624 if ((y = cmcfm()) < 0)
2625 return(y);
2626 ftp_fnc = x;
2627 return(1);
2628
2629 case FTS_CNV: /* Filename conversion */
2630 if ((x = cmkey(fntab,nfntab,"","automatic",xxstring)) < 0)
2631 return(x);
2632 if ((y = cmcfm()) < 0)
2633 return(y);
2634 ftp_cnv = x;
2635 return(1);
2636
2637 case FTS_DBG: /* Debug messages */
2638 return(seton(&ftp_deb));
2639
2640 case FTS_LOG: /* Auto-login */
2641 return(seton(&ftp_log));
2642
2643 case FTS_PSV: /* Passive mode */
2644 return(dosetftppsv());
2645
2646 case FTS_SPC: /* Send port commands */
2647 x = seton(&ftp_spc);
2648 if (x > 0) sendport = ftp_spc;
2649 return(x);
2650
2651 case FTS_TYP: /* Type */
2652 if ((x = cmkey(ftptyp,nftptyp,"","",xxstring)) < 0)
2653 return(x);
2654 if ((y = cmcfm()) < 0) return(y);
2655 ftp_typ = x;
2656 g_ftp_typ = x;
2657 tenex = (ftp_typ == FTT_TEN);
2658 return(1);
2659
2660 case FTS_USN: /* Unique server names */
2661 return(seton(&ftp_usn));
2662
2663 case FTS_VBM: /* Verbose mode */
2664 if ((x = seton(&ftp_vbm)) < 0) /* Per-command copy */
2665 return(x);
2666 ftp_vbx = ftp_vbm; /* Global sticky copy */
2667 return(x);
2668
2669 case FTS_TST: /* "if (testing)" messages */
2670 return(seton(&testing));
2671
2672 case FTS_PRM: /* Send permissions */
2673 return(setonaut(&ftp_prm));
2674
2675 case FTS_AUT: /* Auto-authentication */
2676 return(seton(&ftp_aut));
2677
2678 case FTS_ERR: /* Error action */
2679 if ((x = cmkey(qorp,2,"","",xxstring)) < 0)
2680 return(x);
2681 if ((y = cmcfm()) < 0)
2682 return(y);
2683 ftp_err = x;
2684 return(success = 1);
2685
2686 #ifndef NOCSETS
2687 case FTS_XLA: /* Translation */
2688 return(seton(&ftp_xla));
2689
2690 case FTS_CSR: /* Server charset */
2691 if ((x = cmkey(fcstab,nfilc,"character-set","utf8",xxstring)) < 0)
2692 return(x);
2693 if ((y = cmcfm()) < 0)
2694 return(y);
2695 ftp_csr = x;
2696 ftp_xla = 1; /* Also enable translation */
2697 return(success = 1);
2698 #endif /* NOCSETS */
2699
2700 case FTS_GFT:
2701 return(seton(&get_auto)); /* GET-filetype-switching */
2702
2703 case FTS_DAT:
2704 return(seton(&ftp_dates)); /* Set file dates */
2705
2706 #ifdef FTP_TIMEOUT
2707 case FTS_TMO: /* Timeout */
2708 if ((x = cmnum("Number of seconds","0",10,&z,xxstring)) < 0)
2709 return(x);
2710 if ((y = cmcfm()) < 0)
2711 return(y);
2712 ftp_timeout = z;
2713 return(success = 1);
2714 #endif /* FTP_TIMEOUT */
2715
2716 case FTS_STO: { /* Server time offset */
2717 char * s, * p = NULL;
2718 long k;
2719 if ((x = cmfld("[+-]hh[:mm[:ss]]","+0",&s,xxstring)) < 0)
2720 return(x);
2721 if (!strcmp(s,"+0")) {
2722 s = NULL;
2723 } else if ((x = delta2sec(s,&k)) < 0) { /* Check format */
2724 printf("?Invalid time offset\n");
2725 return(-9);
2726 }
2727 makestr(&p,s); /* Make a safe copy the string */
2728 if ((x = cmcfm()) < 0) { /* Get confirmation */
2729 if (p)
2730 makestr(&p,NULL);
2731 return(x);
2732 }
2733 fts_sto = p; /* Confirmed - set the string. */
2734 return(success = 1);
2735 }
2736 case FTS_APW: {
2737 char * s;
2738 if ((x = cmtxt("Text", "", &s, xxstring)) < 0)
2739 return(x);
2740 makestr(&ftp_apw, *s ? s : NULL);
2741 return(success = 1);
2742 }
2743
2744 case FTS_BUG: {
2745 if ((x = cmkey(ftpbugtab,nftpbug,"","",xxstring)) < 0)
2746 return(x);
2747 switch (x) {
2748 #ifdef CK_SSL
2749 case FTB_SV2:
2750 return seton(&ftp_bug_use_ssl_v2);
2751 case FTB_SV3:
2752 return seton(&ftp_bug_use_ssl_v3);
2753 #endif /* CK_SSL */
2754 default:
2755 return(-2);
2756 }
2757 }
2758
2759 #ifdef FTP_SECURITY
2760 case FTS_CRY: /* Auto-encryption */
2761 return(seton(&ftp_cry));
2762
2763 case FTS_CFW: /* Credential-forwarding */
2764 return(seton(&ftp_cfw));
2765
2766 case FTS_CPL: /* Command protection level */
2767 if ((x = cmkey(ftppro,nftppro,"","",xxstring)) < 0) return(x);
2768 if ((y = cmcfm()) < 0) return(y);
2769 success = fts_cpl(x);
2770 return(success);
2771
2772 case FTS_DPL: /* Data protection level */
2773 if ((x = cmkey(ftppro,nftppro,"","",xxstring)) < 0) return(x);
2774 if ((y = cmcfm()) < 0) return(y);
2775 success = fts_dpl(x);
2776 return(success);
2777
2778 case FTS_ATP: { /* FTP Auth Type */
2779 int i, j, atypes[8];
2780
2781 for (i = 0; i < 8; i++) {
2782 if ((y = cmkey(ftpauth,nftpauth,"",
2783 (i == 0) ? "automatic" : "",
2784 xxstring)) < 0) {
2785 if (y == -3)
2786 break;
2787 return(y);
2788 }
2789 if (i > 0 && (y == FTA_AUTO)) {
2790 printf("?Choice may only be used in first position.\r\n");
2791 return(-9);
2792 }
2793 for (j = 0; j < i; j++) {
2794 if (atypes[j] == y) {
2795 printf("\r\n?Choice has already been used.\r\n");
2796 return(-9);
2797 }
2798 }
2799 atypes[i] = y;
2800 if (y == FTA_AUTO) {
2801 i++;
2802 break;
2803 }
2804 }
2805 if (i < 8)
2806 atypes[i] = 0;
2807 if ((z = cmcfm()) < 0)
2808 return(z);
2809 if (atypes[0] == FTA_AUTO) {
2810 i = 0;
2811 #ifdef FTP_GSSAPI
2812 ftp_auth_type[i++] = FTA_GK5;
2813 #endif /* FTP_GSSAPI */
2814 #ifdef FTP_SRP
2815 ftp_auth_type[i++] = FTA_SRP;
2816 #endif /* FTP_SRP */
2817 #ifdef FTP_KRB4
2818 ftp_auth_type[i++] = FTA_K4;
2819 #endif /* FTP_KRB4 */
2820 #ifdef CK_SSL
2821 ftp_auth_type[i++] = FTA_TLS;
2822 ftp_auth_type[i++] = FTA_SSL;
2823 #endif /* CK_SSL */
2824 ftp_auth_type[i] = 0;
2825 } else {
2826 for (i = 0; i < 8; i++)
2827 ftp_auth_type[i] = atypes[i];
2828 }
2829 return(success = 1);
2830 }
2831
2832 case FTS_SRP:
2833 #ifdef FTP_SRP
2834 if ((x = cmkey(ftpsrp,nftpsrp,"","",xxstring)) < 0)
2835 return(x);
2836 switch (x) {
2837 case SRP_CIPHER:
2838 if ((x = cmkey(ciphertab,nciphertab,"","",xxstring)) < 0)
2839 return(x);
2840 if ((z = cmcfm()) < 0)
2841 return(z);
2842 success = !srp_selcipher(ciphertab[x].kwd);
2843 return(success);
2844 case SRP_HASH:
2845 if ((x = cmkey(hashtab,nhashtab,"","",xxstring)) < 0)
2846 return(x);
2847 if ((z = cmcfm()) < 0)
2848 return(z);
2849 success = !srp_selhash(hashtab[x].kwd);
2850 return(success = 1);
2851 default:
2852 if ((z = cmcfm()) < 0)
2853 return(z);
2854 return(-2);
2855 }
2856 #else /* FTP_SRP */
2857 if ((z = cmcfm()) < 0)
2858 return(z);
2859 return(-2);
2860 #endif /* FTP_SRP */
2861 #endif /* FTP_SECURITY */
2862
2863 case FTS_DIS:
2864 doxdis(2); /* 2 == ftp */
2865 return(success = 1);
2866
2867 default:
2868 return(-2);
2869 }
2870 }
2871
2872 int
ftpbye()2873 ftpbye() {
2874 int x;
2875 if (!connected)
2876 return(1);
2877 if (testing)
2878 printf(" ftp closing %s...\n",ftp_host);
2879 x = ftpclose();
2880 return((x > -1) ? 1 : 0);
2881 }
2882
2883 /* o p e n f t p -- Parse FTP hostname & port and open */
2884
2885 static int
openftp(s,opn_tls)2886 openftp(s,opn_tls) char * s; int opn_tls; {
2887 char c, * p, * hostname = NULL, *hostsave = NULL, * service = NULL;
2888 int i, n, havehost = 0, getval = 0, rc = -9, opn_psv = -1, nologin = 0;
2889 int haveuser = 0;
2890 struct FDB sw, fl, cm;
2891 extern int nnetdir; /* Network services directory */
2892 extern int nhcount; /* Lookup result */
2893 extern char *nh_p[]; /* Network directory entry pointers */
2894 extern char *nh_p2[]; /* Network directory entry nettype */
2895
2896 if (!s) return(-2);
2897 if (!*s) return(-2);
2898
2899 makestr(&hostname,s);
2900 hostsave = hostname;
2901 makestr(&ftp_logname,NULL);
2902 anonymous = 0;
2903 noinit = 0;
2904
2905 debug(F110,"ftp open",hostname,0);
2906
2907 if (sav_psv > -1) { /* Restore prevailing active/passive */
2908 ftp_psv = sav_psv; /* selection in case it was */
2909 sav_psv = -1; /* temporarily overriden by a switch */
2910 }
2911 if (sav_log > -1) { /* Ditto for autologin */
2912 ftp_log = sav_log;
2913 sav_log = -1;
2914 }
2915 cmfdbi(&sw, /* Switches */
2916 _CMKEY,
2917 "Service name or port;\n or switch",
2918 "", /* default */
2919 "", /* addtl string data */
2920 nftpswi, /* addtl numeric data 1: tbl size */
2921 4, /* addtl numeric data 2: none */
2922 xxstring, /* Processing function */
2923 ftpswitab, /* Keyword table */
2924 &fl /* Pointer to next FDB */
2925 );
2926 cmfdbi(&fl, /* A host name or address */
2927 _CMFLD, /* fcode */
2928 "", /* help */
2929 "xYzBoo", /* default */
2930 "", /* addtl string data */
2931 0, /* addtl numeric data 1 */
2932 0, /* addtl numeric data 2 */
2933 xxstring,
2934 NULL,
2935 &cm
2936 );
2937 cmfdbi(&cm, /* Command confirmation */
2938 _CMCFM,
2939 "",
2940 "",
2941 "",
2942 0,
2943 0,
2944 NULL,
2945 NULL,
2946 NULL
2947 );
2948
2949 for (n = 0;; n++) {
2950 rc = cmfdb(&sw); /* Parse a service name or a switch */
2951 if (rc < 0)
2952 goto xopenftp;
2953
2954 if (cmresult.fcode == _CMCFM) { /* Done? */
2955 break;
2956 } else if (cmresult.fcode == _CMFLD) { /* Port */
2957 if (ckstrcmp("xYzBoo",cmresult.sresult,-1,1))
2958 makestr(&service,cmresult.sresult);
2959 else
2960 makestr(&service,opn_tls?"ftps":"ftp");
2961 } else if (cmresult.fcode == _CMKEY) { /* Have a switch */
2962 c = cmgbrk(); /* get break character */
2963 getval = (c == ':' || c == '=');
2964 rc = -9;
2965 if (getval && !(cmresult.kflags & CM_ARG)) {
2966 printf("?This switch does not take arguments\n");
2967 goto xopenftp;
2968 }
2969 if (!getval && (cmresult.kflags & CM_ARG)) {
2970 printf("?This switch requires an argument\n");
2971 goto xopenftp;
2972 }
2973 switch (cmresult.nresult) { /* Switch */
2974 case OPN_ANO: /* /ANONYMOUS */
2975 anonymous++;
2976 nologin = 0;
2977 break;
2978 case OPN_NIN: /* /NOINIT */
2979 noinit++;
2980 break;
2981 case OPN_NOL: /* /NOLOGIN */
2982 nologin++;
2983 anonymous = 0;
2984 makestr(&ftp_logname,NULL);
2985 break;
2986 case OPN_PSW: /* /PASSWORD */
2987 if (!anonymous) /* Don't log real passwords */
2988 debok = 0;
2989 rc = cmfld("Password for FTP server","",&p,xxstring);
2990 if (rc == -3) {
2991 makestr(&ftp_tmp,NULL);
2992 } else if (rc < 0) {
2993 goto xopenftp;
2994 } else {
2995 makestr(&ftp_tmp,brstrip(p));
2996 nologin = 0;
2997 }
2998 break;
2999 case OPN_USR: /* /USER */
3000 rc = cmfld("Username for FTP server","",&p,xxstring);
3001 if (rc == -3) {
3002 makestr(&ftp_logname,NULL);
3003 } else if (rc < 0) {
3004 goto xopenftp;
3005 } else {
3006 nologin = 0;
3007 anonymous = 0;
3008 haveuser = 1;
3009 makestr(&ftp_logname,brstrip(p));
3010 }
3011 break;
3012 case OPN_ACC:
3013 rc = cmfld("Account for FTP server","",&p,xxstring);
3014 if (rc == -3) {
3015 makestr(&ftp_acc,NULL);
3016 } else if (rc < 0) {
3017 goto xopenftp;
3018 } else {
3019 makestr(&ftp_acc,brstrip(p));
3020 }
3021 break;
3022 case OPN_ACT:
3023 opn_psv = 0;
3024 break;
3025 case OPN_PSV:
3026 opn_psv = 1;
3027 break;
3028 case OPN_TLS:
3029 opn_tls = 1;
3030 break;
3031 default:
3032 break;
3033 }
3034 }
3035 if (n == 0) { /* After first time through */
3036 cmfdbi(&sw, /* accept only switches */
3037 _CMKEY,
3038 "\nCarriage return to confirm to command, or switch",
3039 "",
3040 "",
3041 nftpswi,
3042 4,
3043 xxstring,
3044 ftpswitab,
3045 &cm
3046 );
3047 }
3048 }
3049 #ifdef COMMENT
3050 debug(F100,"ftp openftp while exit","",0);
3051 rc = cmcfm();
3052 debug(F101,"ftp openftp cmcfm rc","",rc);
3053 if (rc < 0)
3054 goto xopenftp;
3055 #endif /* COMMENT */
3056
3057 if (opn_psv > -1) { /* /PASSIVE or /ACTIVE switch given */
3058 sav_psv = ftp_psv;
3059 ftp_psv = opn_psv;
3060 }
3061 if (nologin || haveuser) { /* /NOLOGIN or /USER switch given */
3062 sav_log = ftp_log;
3063 ftp_log = haveuser ? 1 : 0;
3064 }
3065 if (*hostname == '=') { /* Bypass directory lookup */
3066 hostname++; /* if hostname starts with '=' */
3067 havehost++;
3068 } else if (isdigit(*hostname)) { /* or if it starts with a digit */
3069 havehost++;
3070 }
3071 if (!service)
3072 makestr(&service,opn_tls?"ftps":"ftp");
3073
3074 #ifndef NODIAL
3075 if (!havehost && nnetdir > 0) { /* If there is a networks directory */
3076 lunet(hostname); /* Look up the name */
3077 debug(F111,"ftp openftp lunet",hostname,nhcount);
3078 if (nhcount == 0) {
3079 if (testing)
3080 printf(" ftp open trying \"%s %s\"...\n",hostname,service);
3081 success = ftpopen(hostname,service,opn_tls);
3082 debug(F101,"ftp openftp A ftpopen success","",success);
3083 rc = success;
3084 } else {
3085 int found = 0;
3086 for (i = 0; i < nhcount; i++) {
3087 if (nh_p2[i]) /* If network type specified */
3088 if (ckstrcmp(nh_p2[i],"tcp/ip",strlen(nh_p2[i]),0))
3089 continue;
3090 found++;
3091 makestr(&hostname,nh_p[i]);
3092 debug(F111,"ftpopen lunet substitution",hostname,i);
3093 if (testing)
3094 printf(" ftp open trying \"%s %s\"...\n",hostname,service);
3095 success = ftpopen(hostname,service,opn_tls);
3096 debug(F101,"ftp openftp B ftpopen success","",success);
3097 rc = success;
3098 if (success)
3099 break;
3100 }
3101 if (!found) { /* E.g. if no network types match */
3102 if (testing)
3103 printf(" ftp open trying \"%s %s\"...\n",hostname,service);
3104 success = ftpopen(hostname,service,opn_tls);
3105 debug(F101,"ftp openftp C ftpopen success","",success);
3106 rc = success;
3107 }
3108 }
3109 } else {
3110 #endif /* NODIAL */
3111 if (testing)
3112 printf(" ftp open trying \"%s %s\"...\n",hostname,service);
3113 success = ftpopen(hostname,service,opn_tls);
3114 debug(F111,"ftp openftp D ftpopen success",hostname,success);
3115 debug(F111,"ftp openftp D ftpopen connected",hostname,connected);
3116 rc = success;
3117 #ifndef NODIAL
3118 }
3119 #endif /* NODIAL */
3120
3121 xopenftp:
3122 debug(F101,"ftp openftp xopenftp rc","",rc);
3123 if (hostsave) free(hostsave);
3124 if (service) free(service);
3125 if (rc < 0 && ftp_logname) {
3126 free(ftp_logname);
3127 ftp_logname = NULL;
3128 }
3129 if (ftp_tmp) {
3130 free(ftp_tmp);
3131 ftp_tmp = NULL;
3132 }
3133 return(rc);
3134 }
3135
3136 VOID /* 12 Aug 2007 */
doftpglobaltype(x)3137 doftpglobaltype(x) int x; {
3138 ftp_xfermode = XMODE_M; /* Set manual FTP transfer mode */
3139 ftp_typ = x; /* Used by top-level BINARY and */
3140 g_ftp_typ = x; /* ASCII commands. */
3141 get_auto = 0;
3142 forcetype = 1;
3143 }
3144
3145 int
doftpacct()3146 doftpacct() {
3147 int x;
3148 char * s;
3149 if ((x = cmtxt("Remote account", "", &s, xxstring)) < 0)
3150 return(x);
3151 CHECKCONN();
3152 makestr(&ftp_acc,brstrip(s));
3153 if (testing)
3154 printf(" ftp account: \"%s\"\n",ftp_acc);
3155 success = (ftpcmd("ACCT",ftp_acc,-1,-1,ftp_vbm) == REPLY_COMPLETE);
3156 return(success);
3157 }
3158
3159 int
doftpusr()3160 doftpusr() { /* Log in as USER */
3161 extern char uidbuf[];
3162 extern char pwbuf[];
3163 extern int pwflg, pwcrypt;
3164 int x;
3165 char *s, * acct = "";
3166
3167 debok = 0; /* Don't log */
3168
3169 if ((x = cmfld("Remote username or ID",uidbuf,&s,xxstring)) < 0)
3170 return(x);
3171 ckstrncpy(line,brstrip(s),LINBUFSIZ); /* brstrip: 15 Jan 2003 */
3172 if ((x = cmfld("Remote password","",&s,xxstring)) < 0) {
3173 if (x == -3) { /* no input */
3174 if ( pwbuf[0] && pwflg ) {
3175 ckstrncpy(tmpbuf,(char *)pwbuf,TMPBUFSIZ);
3176 #ifdef OS2
3177 if ( pwcrypt )
3178 ck_encrypt((char *)tmpbuf);
3179 #endif /* OS2 */
3180 }
3181 } else {
3182 return(x);
3183 }
3184 } else {
3185 ckstrncpy(tmpbuf,brstrip(s),TMPBUFSIZ);
3186 }
3187 if ((x = cmtxt("Remote account\n or Enter or CR to confirm the command",
3188 "", &s, xxstring)) < 0)
3189 return(x);
3190 CHECKCONN();
3191 if (*s) {
3192 x = strlen(tmpbuf);
3193 if (x > 0) {
3194 acct = &tmpbuf[x+2];
3195 ckstrncpy(acct,brstrip(s),TMPBUFSIZ - x - 2);
3196 }
3197 }
3198 if (testing)
3199 printf(" ftp user \"%s\" password \"%s\"...\n",line,tmpbuf);
3200 success = ftp_user(line,tmpbuf,acct);
3201 #ifdef CKLOGDIAL
3202 dologftp();
3203 #endif /* CKLOGDIAL */
3204 return(success);
3205 }
3206
3207 /* DO (various FTP commands)... */
3208
3209 int
doftptyp(type)3210 doftptyp(type) int type; { /* TYPE */
3211 CHECKCONN();
3212 ftp_typ = type;
3213 changetype(ftp_typ,ftp_vbm);
3214 debug(F101,"doftptyp changed type","",type);
3215 return(1);
3216 }
3217
3218 static int
doftpxmkd(s,vbm)3219 doftpxmkd(s,vbm) char * s; int vbm; { /* MKDIR action */
3220 int lcs = -1, rcs = -1;
3221 #ifndef NOCSETS
3222 if (ftp_xla) {
3223 lcs = ftp_csl;
3224 if (lcs < 0) lcs = fcharset;
3225 rcs = ftp_csx;
3226 if (rcs < 0) rcs = ftp_csr;
3227 }
3228 #endif /* NOCSETS */
3229 debug(F110,"ftp doftpmkd",s,0);
3230 if (ftpcmd("MKD",s,lcs,rcs,vbm) == REPLY_COMPLETE)
3231 return(success = 1);
3232 if (ftpcode == 500 || ftpcode == 502) {
3233 if (!quiet)
3234 printf("MKD command not recognized, trying XMKD\n");
3235 if (ftpcmd("XMKD",s,lcs,rcs,vbm) == REPLY_COMPLETE)
3236 return(success = 1);
3237 }
3238 return(success = 0);
3239 }
3240
3241 static int
doftpmkd()3242 doftpmkd() { /* MKDIR parse */
3243 int x;
3244 char * s;
3245 if ((x = cmtxt("Remote directory name", "", &s, xxstring)) < 0)
3246 return(x);
3247 CHECKCONN();
3248 ckstrncpy(line,s,LINBUFSIZ);
3249 if (testing)
3250 printf(" ftp mkdir \"%s\"...\n",line);
3251 return(success = doftpxmkd(line,-1));
3252 }
3253
3254 static int
doftprmd()3255 doftprmd() { /* RMDIR */
3256 int x, lcs = -1, rcs = -1;
3257 char * s;
3258 if ((x = cmtxt("Remote directory", "", &s, xxstring)) < 0)
3259 return(x);
3260 CHECKCONN();
3261 ckstrncpy(line,s,LINBUFSIZ);
3262 if (testing)
3263 printf(" ftp rmdir \"%s\"...\n",line);
3264 #ifndef NOCSETS
3265 if (ftp_xla) {
3266 lcs = ftp_csl;
3267 if (lcs < 0) lcs = fcharset;
3268 rcs = ftp_csx;
3269 if (rcs < 0) rcs = ftp_csr;
3270 }
3271 #endif /* NOCSETS */
3272 if (ftpcmd("RMD",line,lcs,rcs,ftp_vbm) == REPLY_COMPLETE)
3273 return(success = 1);
3274 if (ftpcode == 500 || ftpcode == 502) {
3275 if (!quiet)
3276 printf("RMD command not recognized, trying XMKD\n");
3277 success = (ftpcmd("XRMD",line,lcs,rcs,ftp_vbm) == REPLY_COMPLETE);
3278 } else
3279 success = 0;
3280 return(success);
3281 }
3282
3283 static int
doftpren()3284 doftpren() { /* RENAME */
3285 int x;
3286 char * s;
3287 if ((x = cmfld("Remote filename","",&s,xxstring)) < 0)
3288 return(x);
3289 ckstrncpy(line,s,LINBUFSIZ);
3290 if ((x = cmfld("New name for remote file","",&s,xxstring)) < 0)
3291 return(x);
3292 ckstrncpy(tmpbuf,s,TMPBUFSIZ);
3293 if ((x = cmcfm()) < 0)
3294 return(x);
3295 CHECKCONN();
3296 if (testing)
3297 printf(" ftp rename \"%s\" (to) \"%s\"...\n",line,tmpbuf);
3298 success = ftp_rename(line,tmpbuf);
3299 return(success);
3300 }
3301
3302 int
doftpres()3303 doftpres() { /* RESET (log out without close) */
3304 int x;
3305 if ((x = cmcfm()) < 0)
3306 return(x);
3307 CHECKCONN();
3308 if (testing)
3309 printf(" ftp reset...\n");
3310 return(success = ftp_reset());
3311 }
3312
3313 static int
doftpxhlp()3314 doftpxhlp() { /* HELP */
3315 int x;
3316 char * s;
3317 if ((x = cmtxt("Command name", "", &s, xxstring)) < 0)
3318 return(x);
3319 CHECKCONN();
3320 ckstrncpy(line,s,LINBUFSIZ);
3321 if (testing)
3322 printf(" ftp help \"%s\"...\n",line);
3323 /* No need to translate -- all FTP commands are ASCII */
3324 return(success = (ftpcmd("HELP",line,0,0,1) == REPLY_COMPLETE));
3325 }
3326
3327 static int
doftpdir(cx)3328 doftpdir(cx) int cx; { /* [V]DIRECTORY */
3329 int x, lcs = 0, rcs = 0, xlate = 0;
3330 char * p, * s, * m = "";
3331 if (cx == FTP_VDI) {
3332 switch (servertype) {
3333 case SYS_VMS:
3334 case SYS_DOS:
3335 case SYS_TOPS10:
3336 case SYS_TOPS20:
3337 m = "*.*";
3338 break;
3339 default:
3340 m = "*";
3341 }
3342 }
3343 if ((x = cmtxt("Remote filespec",m,&s,xxstring)) < 0)
3344 return(x);
3345 if ((x = remtxt(&s)) < 0)
3346 return(x);
3347 #ifdef NOCSETS
3348 xlate = 0;
3349 #else
3350 xlate = ftp_xla;
3351 #endif /* NOCSETS */
3352 line[0] = NUL;
3353 ckstrncpy(line,s,LINBUFSIZ);
3354 s = line;
3355 CHECKCONN();
3356
3357 #ifndef NOCSETS
3358 if (xlate) { /* SET FTP CHARACTER-SET-TRANSLATION */
3359 lcs = ftp_csl; /* Local charset */
3360 if (lcs < 0) lcs = fcharset;
3361 if (lcs < 0) xlate = 0;
3362 }
3363 if (xlate) { /* Still ON? */
3364 rcs = ftp_csx; /* Remote (Server) charset */
3365 if (rcs < 0) rcs = ftp_csr;
3366 if (rcs < 0) xlate = 0;
3367 }
3368 #endif /* NOCSETS */
3369
3370 if (testing) {
3371 p = s;
3372 if (!p) p = "";
3373 if (*p)
3374 printf("Directory of files %s at %s:\n", line, ftp_host);
3375 else
3376 printf("Directory of files at %s:\n", ftp_host);
3377 }
3378 debug(F111,"doftpdir",s,cx);
3379
3380 if (cx == FTP_DIR) {
3381 /* Translation of line[] is done inside recvrequest() */
3382 /* when it calls ftpcmd(). */
3383 return(success =
3384 (recvrequest("LIST","-",s,"wb",0,0,NULL,xlate,lcs,rcs) == 0));
3385 }
3386 success = 1; /* VDIR - one file at a time... */
3387 p = (char *)remote_files(1,(CHAR *)s,NULL,0); /* Get the file list */
3388 cancelgroup = 0;
3389 if (!ftp_vbm && !quiet)
3390 printlines = 1;
3391 while (p && !cancelfile && !cancelgroup) { /* STAT one file */
3392 if (ftpcmd("STAT",p,lcs,rcs,ftp_vbm) < 0) {
3393 success = 0;
3394 break;
3395 }
3396 p = (char *)remote_files(0,NULL,NULL,0); /* Get next file */
3397 debug(F110,"ftp vdir file",s,0);
3398 }
3399 return(success);
3400 }
3401
3402 static int
doftppwd()3403 doftppwd() { /* PWD */
3404 int x, lcs = -1, rcs = -1;
3405 #ifndef NOCSETS
3406 if (ftp_xla) {
3407 lcs = ftp_csl;
3408 if (lcs < 0) lcs = fcharset;
3409 rcs = ftp_csx;
3410 if (rcs < 0) rcs = ftp_csr;
3411 }
3412 #endif /* NOCSETS */
3413 if ((x = cmcfm()) < 0)
3414 return(x);
3415 CHECKCONN();
3416 if (ftpcmd("PWD",NULL,lcs,rcs,1) == REPLY_COMPLETE) {
3417 success = 1;
3418 } else if (ftpcode == 500 || ftpcode == 502) {
3419 if (ftp_deb)
3420 printf("PWD command not recognized, trying XPWD\n");
3421 success = (ftpcmd("XPWD",NULL,lcs,rcs,1) == REPLY_COMPLETE);
3422 }
3423 return(success);
3424 }
3425
3426 static int
doftpcwd(s,vbm)3427 doftpcwd(s,vbm) char * s; int vbm; { /* CD (CWD) */
3428 int lcs = -1, rcs = -1;
3429 #ifndef NOCSETS
3430 if (ftp_xla) {
3431 lcs = ftp_csl;
3432 if (lcs < 0) lcs = fcharset;
3433 rcs = ftp_csx;
3434 if (rcs < 0) rcs = ftp_csr;
3435 }
3436 #endif /* NOCSETS */
3437
3438 debug(F110,"ftp doftpcwd",s,0);
3439 if (ftpcmd("CWD",s,lcs,rcs,vbm) == REPLY_COMPLETE)
3440 return(success = 1);
3441 if (ftpcode == 500 || ftpcode == 502) {
3442 if (!quiet)
3443 printf("CWD command not recognized, trying XCWD\n");
3444 if (ftpcmd("XCWD",s,lcs,rcs,vbm) == REPLY_COMPLETE)
3445 return(success = 1);
3446 }
3447 return(success = 0);
3448 }
3449
3450 static int
doftpcdup()3451 doftpcdup() { /* CDUP */
3452 debug(F100,"ftp doftpcdup","",0);
3453 if (ftpcmd("CDUP",NULL,0,0,1) == REPLY_COMPLETE)
3454 return(success = 1);
3455 if (ftpcode == 500 || ftpcode == 502) {
3456 if (!quiet)
3457 printf("CDUP command not recognized, trying XCUP\n");
3458 if (ftpcmd("XCUP",NULL,0,0,1) == REPLY_COMPLETE)
3459 return(success = 1);
3460 }
3461 return(success = 0);
3462 }
3463
3464 /* s y n c d i r -- Synchronizes client & server directories */
3465
3466 /*
3467 Call with:
3468 local = pointer to pathname of local file to be sent.
3469 sim = 1 for simulation, 0 for real uploading.
3470 Returns 0 on failure, 1 on success.
3471
3472 The 'local' argument is relative to the initial directory of the MPUT,
3473 i.e. the root of the tree being uploaded. If the directory of the
3474 argument file is different from the directory of the previous file
3475 (which is stored in global putpath[]), this routine does the appropriate
3476 CWDs, CDUPs, and/or MKDIRs to position the FTP server in the same place.
3477 */
3478 static int cdlevel = 0, cdsimlvl = 0; /* Tree-level trackers */
3479
3480 static int
syncdir(local,sim)3481 syncdir(local,sim) char * local; int sim; {
3482 char buf[CKMAXPATH+1];
3483 char tmp[CKMAXPATH+1];
3484 char msgbuf[CKMAXPATH+64];
3485 char c, * p = local, * s = buf, * q = buf, * psep, * ssep;
3486 int i, k = 0, done = 0, itsadir = 0, saveq;
3487
3488 debug(F110,"ftp syncdir local (new)",local,0);
3489 debug(F110,"ftp syncdir putpath (old)",putpath,0);
3490
3491 itsadir = isdir(local); /* Is the local file a directory? */
3492 saveq = quiet;
3493
3494 while ((*s = *p)) { /* Copy the argument filename */
3495 if (++k == CKMAXPATH) /* so we can poke it. */
3496 return(-1);
3497 if (*s == '/') /* Pointer to rightmost dirsep */
3498 q = s;
3499 s++;
3500 p++;
3501 }
3502 if (!itsadir) /* If it's a regular file */
3503 *q = NUL; /* keep just the path part */
3504
3505 debug(F110,"ftp syncdir buf",buf,0);
3506 if (!strcmp(buf,putpath)) { /* Same path as previous file? */
3507 if (itsadir) { /* This file is a directory? */
3508 if (doftpcwd(local,0)) { /* Try to CD to it */
3509 doftpcdup(); /* Worked - CD back up */
3510 } else if (sim) { /* Simulating... */
3511 if (fdispla == XYFD_B) {
3512 printf("WOULD CREATE DIRECTORY %s\n",local);
3513 } else if (fdispla) {
3514 ckmakmsg(msgbuf,CKMAXPATH,
3515 "WOULD CREATE DIRECTORY",local,NULL,NULL);
3516 ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,msgbuf);
3517 }
3518 /* See note above */
3519 return(0);
3520 } else if (!doftpxmkd(local,0)) { /* Can't CD - try to create */
3521 return(0);
3522 } else { /* Remote directory created OK */
3523 if (fdispla == XYFD_B) {
3524 printf("CREATED DIRECTORY %s\n",local);
3525 } else if (fdispla) {
3526 ckmakmsg(msgbuf,CKMAXPATH+64,
3527 "CREATED DIRECTORY ",local,NULL,NULL);
3528 ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,msgbuf);
3529 }
3530 }
3531 }
3532 debug(F110,"ftp syncdir no change",buf,0);
3533 return(1); /* Yes, done. */
3534 }
3535 ckstrncpy(tmp,buf,CKMAXPATH+1); /* Make a safe (pre-poked) copy */
3536 debug(F110,"ftp syncdir new path",buf,0); /* for later (see end) */
3537
3538 p = buf; /* New */
3539 s = putpath; /* Old */
3540
3541 debug(F110,"ftp syncdir A (old) s",s,0); /* Previous */
3542 debug(F110,"ftp syncdir A (new) p",p,0); /* New */
3543
3544 psep = buf;
3545 ssep = putpath;
3546 while (*p != NUL && *s != NUL && *p == *s) {
3547 if (*p == '/') { psep = p+1; ssep = s+1; }
3548 p++,s++;
3549 }
3550 /*
3551 psep and ssep point to the first path segment that differs.
3552 We have to do as many CDUPs as there are path segments in ssep.
3553 then we have to do as many MKDs and CWDs as there are segments in psep.
3554 */
3555 s = ssep;
3556 p = psep;
3557
3558 debug(F110,"ftp syncdir B (old) s",s,0); /* Previous */
3559 debug(F110,"ftp syncdir B (new) p",p,0); /* New */
3560
3561 /* p and s now point to the leftmost spot where the paths differ */
3562
3563 if (*s) { /* We have to back up */
3564 k = 1; /* How many levels counting this one */
3565 while ((c = *s++)) { /* Count dirseps remaining in prev */
3566 if (c == '/' && *s)
3567 k++;
3568 }
3569 debug(F101,"ftp syncdir levels up","",k);
3570
3571 for (i = 1; i <= k; i++) { /* Do that many CDUPs */
3572 debug(F111,"ftp syncdir CDUP A",p,i);
3573 if (fdispla == XYFD_B)
3574 printf(" CDUP\n");
3575 if (sim && cdsimlvl) {
3576 cdsimlvl--;
3577 } else {
3578 if (!doftpcdup()) {
3579 quiet = saveq;
3580 return(0);
3581 }
3582 }
3583 cdlevel--;
3584 }
3585 if (!*p) /* If we don't have to go down */
3586 goto xcwd; /* we're done. */
3587 }
3588 #ifdef COMMENT
3589 while (p > buf && *p && *p != '/') /* If in middle of segment */
3590 p--; /* back up to beginning */
3591 if (*p == '/') /* and terminate there */
3592 p++;
3593 #endif /* COMMENT */
3594
3595 debug(F110,"ftp syncdir NEW PATH",p,0);
3596
3597 s = p; /* Point to start of new down path. */
3598 while (1) { /* Loop through characters. */
3599 if (*s == '/' || !*s) { /* Have a segment. */
3600 if (!*s) /* If end of string, */
3601 done++; /* after this segment we're done. */
3602 else
3603 *s = NUL; /* NUL out the separator. */
3604 if (*p) { /* If segment is not empty */
3605 debug(F110,"ftp syncdir down segment",p,0);
3606 if (!doftpcwd(p,0)) { /* Try to CD to it */
3607 if (sim) {
3608 if (fdispla == XYFD_B) {
3609 printf(" WOULD CREATE DIRECTORY %s\n",local);
3610 } else if (fdispla) {
3611 ckmakmsg(msgbuf,CKMAXPATH,
3612 "WOULD CREATE DIRECTORY",
3613 local,NULL,NULL);
3614 ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,msgbuf);
3615 }
3616 cdsimlvl++;
3617 } else {
3618 if (!doftpxmkd(p,0)) { /* Can't CD - try to create */
3619 debug(F110,"ftp syncdir mkdir failed",p,0);
3620 /*
3621 Suppose we are executing SEND /RECURSIVE. Locally we have a directory
3622 FOO but the remote has a regular file with the same name. We can't CD
3623 to it, can't MKDIR it either. There's no way out but to fail and let
3624 the user handle the problem.
3625 */
3626 quiet = saveq;
3627 return(0);
3628 }
3629 debug(F110,"ftp syncdir mkdir OK",p,0);
3630 if (fdispla == XYFD_B) {
3631 printf(" CREATED DIRECTORY %s\n",p);
3632 } else if (fdispla) {
3633 ckmakmsg(msgbuf,CKMAXPATH,
3634 "CREATED DIRECTORY ",p,NULL,NULL);
3635 ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,msgbuf);
3636 }
3637 if (!doftpcwd(p,0)) { /* Try again to CD */
3638 debug(F110,"ftp syncdir CD failed",p,0);
3639 quiet = saveq;
3640 return(0);
3641 }
3642 if (fdispla == XYFD_B) printf(" CWD %s\n",p);
3643 debug(F110,"ftp syncdir CD OK",p,0);
3644 }
3645 }
3646 cdlevel++;
3647 }
3648 if (done) /* Quit if no next segment */
3649 break;
3650 p = s+1; /* Point to next segment */
3651 }
3652 s++; /* Point to next source char */
3653 }
3654
3655 xcwd:
3656 ckstrncpy(putpath,tmp,CKMAXPATH+1); /* All OK - make this the new path */
3657 quiet = saveq;
3658 return(1);
3659 }
3660
3661 #ifdef DOUPDATE
3662 #ifdef DEBUG
3663 static VOID
dbtime(s,xx)3664 dbtime(s,xx) char * s; struct tm * xx; { /* Write struct tm to debug log */
3665 if (deblog) {
3666 debug(F111,"ftp year ",s,xx->tm_year);
3667 debug(F111,"ftp month",s,xx->tm_mon);
3668 debug(F111,"ftp day ",s,xx->tm_mday);
3669 debug(F111,"ftp hour ",s,xx->tm_hour);
3670 debug(F111,"ftp min ",s,xx->tm_min);
3671 debug(F111,"ftp sec ",s,xx->tm_sec);
3672 }
3673 }
3674 #endif /* DEBUG */
3675
3676 /* t m c o m p a r e -- Compare two struct tm's */
3677
3678 /* Like strcmp() but for struct tm's */
3679 /* Returns -1 if xx < yy, 0 if they are equal, 1 if xx > yy */
3680
3681 static int
tmcompare(xx,yy)3682 tmcompare(xx,yy) struct tm * xx, * yy; {
3683
3684 if (xx->tm_year < yy->tm_year) /* First year less than second */
3685 return(-1);
3686 if (xx->tm_year > yy->tm_year) /* First year greater than second */
3687 return(1);
3688
3689 /* Years are equal so compare months */
3690
3691 if (xx->tm_mon < yy->tm_mon) /* And so on... */
3692 return(-1);
3693 if (xx->tm_mon > yy->tm_mon)
3694 return(1);
3695
3696 if (xx->tm_mday < yy->tm_mday)
3697 return(-1);
3698 if (xx->tm_mday > yy->tm_mday)
3699 return(1);
3700
3701 if (xx->tm_hour < yy->tm_hour)
3702 return(-1);
3703 if (xx->tm_hour > yy->tm_hour)
3704 return(1);
3705
3706 if (xx->tm_min < yy->tm_min)
3707 return(-1);
3708 if (xx->tm_min > yy->tm_min)
3709 return(1);
3710
3711 if (xx->tm_sec < yy->tm_sec)
3712 return(-1);
3713 if (xx->tm_sec > yy->tm_sec)
3714 return(1);
3715
3716 return(0);
3717 }
3718 #endif /* DOUPDATE */
3719
3720 #ifndef HAVE_TIMEGM /* For platforms that do not have timegm() */
3721 static CONST int MONTHDAYS[] = { /* Number of days in each month. */
3722 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
3723 };
3724
3725 /* Macro for whether a given year is a leap year. */
3726 #define ISLEAP(year) \
3727 (((year) % 4) == 0 && (((year) % 100) != 0 || ((year) % 400) == 0))
3728 #endif /* HAVE_TIMEGM */
3729
3730 /* m k u t i m e -- Like mktime() but argument is already UTC */
3731
3732 static time_t
3733 #ifdef CK_ANSIC
mkutime(struct tm * tm)3734 mkutime(struct tm * tm)
3735 #else
3736 mkutime(tm) struct tm * tm;
3737 #endif /* CK_ANSIC */
3738 /* mkutime */ {
3739 #ifdef HAVE_TIMEGM
3740 return(timegm(tm)); /* Have system service, use it. */
3741 #else
3742 /*
3743 Contributed by Russ Allbery (rra@stanford.edu), used by permission.
3744 Given a struct tm representing a calendar time in UTC, convert it to
3745 seconds since epoch. Returns (time_t) -1 if the time is not
3746 convertable. Note that this function does not canonicalize the provided
3747 struct tm, nor does it allow out-of-range values or years before 1970.
3748 Result should be identical with timegm().
3749 */
3750 time_t result = 0;
3751 int i;
3752 /*
3753 We do allow some ill-formed dates, but we don't do anything special
3754 with them and our callers really shouldn't pass them to us. Do
3755 explicitly disallow the ones that would cause invalid array accesses
3756 or other algorithm problems.
3757 */
3758 #ifdef DEBUG
3759 if (deblog) {
3760 debug(F101,"mkutime tm_mon","",tm->tm_mon);
3761 debug(F101,"mkutime tm_year","",tm->tm_year);
3762 }
3763 #endif /* DEBUG */
3764 if (tm->tm_mon < 0 || tm->tm_mon > 11 || tm->tm_year < 70)
3765 return((time_t) -1);
3766
3767 /* Convert to time_t. */
3768 for (i = 1970; i < tm->tm_year + 1900; i++)
3769 result += 365 + ISLEAP(i);
3770 for (i = 0; i < tm->tm_mon; i++)
3771 result += MONTHDAYS[i];
3772 if (tm->tm_mon > 1 && ISLEAP(tm->tm_year + 1900))
3773 result++;
3774 result = 24 * (result + tm->tm_mday - 1) + tm->tm_hour;
3775 result = 60 * result + tm->tm_min;
3776 result = 60 * result + tm->tm_sec;
3777 debug(F101,"mkutime result","",result);
3778 return(result);
3779 #endif /* HAVE_TIMEGM */
3780 }
3781
3782
3783 /*
3784 s e t m o d t i m e -- Set file modification time.
3785
3786 f = char * filename;
3787 t = time_t date/time to set (Secs since 19700101 0:00:00 UTC, NOT local)
3788
3789 UNIX-specific; isolates mainline code from hideous #ifdefs.
3790 Returns:
3791 0 on success,
3792 -1 on error.
3793
3794 */
3795 static int
3796 #ifdef CK_ANSIC
setmodtime(char * f,time_t t)3797 setmodtime(char * f, time_t t)
3798 #else
3799 setmodtime(f,t) char * f; time_t t;
3800 #endif /* CK_ANSIC */
3801 /* setmodtime */ {
3802 #ifdef NT
3803 struct _stat sb;
3804 #else /* NT */
3805 struct stat sb;
3806 #endif /* NT */
3807 int x, rc = 0;
3808 #ifdef BSD44
3809 struct timeval tp[2];
3810 #else /* def BSD44 */
3811 #ifdef V7
3812 struct utimbuf {
3813 time_t timep[2];
3814 } tp;
3815 #else /* def V7 */
3816 #ifdef SYSUTIMEH
3817 #ifdef NT
3818 struct _utimbuf tp;
3819 #else /* NT */
3820 struct utimbuf tp;
3821 #endif /* NT */
3822 #else /* def SYSUTIMEH */
3823 #ifdef VMS
3824 struct utimbuf tp;
3825 #define SYSUTIMEH /* Our utimbuf matches this one. */
3826 #else /* def VMS */
3827 struct utimbuf {
3828 time_t atime;
3829 time_t mtime;
3830 } tp;
3831 #endif /* def VMS [else] */
3832 #endif /* def SYSUTIMEH [else] */
3833 #endif /* def V7 [else] */
3834 #endif /* def BSD44 [else] */
3835
3836 if (stat(f,&sb) < 0) {
3837 debug(F111,"setmodtime stat failure",f,errno);
3838 return(-1);
3839 }
3840 #ifdef BSD44
3841 tp[0].tv_sec = sb.st_atime; /* Access time first */
3842 tp[1].tv_sec = t; /* Update time second */
3843 debug(F111,"setmodtime BSD44",f,t);
3844 #else
3845 #ifdef V7
3846 tp.timep[0] = t; /* Set modif. time to creation date */
3847 tp.timep[1] = sb.st_atime; /* Don't change the access time */
3848 debug(F111,"setmodtime V7",f,t);
3849 #else
3850 #ifdef SYSUTIMEH
3851 tp.modtime = t; /* Set modif. time to creation date */
3852 tp.actime = sb.st_atime; /* Don't change the access time */
3853 debug(F111,"setmodtime SYSUTIMEH",f,t);
3854 #else
3855 tp.mtime = t; /* Set modif. time to creation date */
3856 tp.atime = sb.st_atime; /* Don't change the access time */
3857 debug(F111,"setmodtime (other)",f,t);
3858 #endif /* SYSUTIMEH */
3859 #endif /* V7 */
3860 #endif /* BSD44 */
3861
3862 /* Try to set the file date */
3863
3864 #ifdef BSD44
3865 x = utimes(f,tp);
3866 debug(F111,"setmodtime utimes()","BSD44",x);
3867 #else
3868 #ifdef IRIX65
3869 {
3870 /*
3871 The following produces the nonsensical warning:
3872 Argument of type "const struct utimbuf *" is incompatible with
3873 parameter of type "const struct utimbuf *". If you can make it
3874 go away, be my guest.
3875 */
3876 const struct utimbuf * t2 = &tp;
3877 x = utime(f,t2);
3878 }
3879 #else
3880 x = utime(f,&tp);
3881 debug(F111,"setmodtime utime()","other",x);
3882 #endif /* IRIX65 */
3883 #endif /* BSD44 */
3884 if (x)
3885 rc = -1;
3886
3887 debug(F101,"setmodtime result","",rc);
3888 return(rc);
3889 }
3890
3891
3892 /*
3893 c h k m o d t i m e -- Check/Set file modification time.
3894
3895 fc = function code:
3896 0 = Check; returns:
3897 -1 on error,
3898 0 if local older than remote,
3899 1 if modtimes are equal,
3900 2 if local newer than remote.
3901 1 = Set (local file's modtime from remote's); returns:
3902 -1 on error,
3903 0 on success.
3904 */
3905 static int
chkmodtime(local,remote,fc)3906 chkmodtime(local,remote,fc) char * local, * remote; int fc; {
3907 #ifdef NT
3908 struct _stat statbuf;
3909 #else /* NT */
3910 struct stat statbuf;
3911 #endif /* NT */
3912 struct tm * tmlocal = NULL;
3913 struct tm tmremote;
3914 int rc = 0, havedate = 0, lcs = -1, rcs = -1, flag = 0;
3915 char * s, timebuf[64];
3916
3917 debug(F111,"chkmodtime",local,mdtmok);
3918 if (!mdtmok) /* Server supports MDTM? */
3919 return(-1); /* No don't bother. */
3920
3921 #ifndef NOCSETS
3922 if (ftp_xla) {
3923 lcs = ftp_csl;
3924 if (lcs < 0) lcs = fcharset;
3925 rcs = ftp_csx;
3926 if (rcs < 0) rcs = ftp_csr;
3927 }
3928 #endif /* NOCSETS */
3929
3930 if (fc == 0) {
3931 rc = stat(local,&statbuf);
3932 if (rc == 0) { /* Get local file's mod time */
3933 /* Convert to struct tm */
3934 tmlocal = gmtime((time_t *)&statbuf.st_mtime);
3935 #ifdef DEBUG
3936 if (tmlocal) {
3937 dbtime(local,tmlocal);
3938 }
3939 #endif /* DEBUG */
3940 }
3941 }
3942 /* Get remote file's mod time as yyyymmddhhmmss */
3943
3944 if (havemdtm) { /* Already got it from MLSD? */
3945 s = havemdtm;
3946 flag++;
3947 } else if (ftpcmd("MDTM",remote,lcs,rcs,0) == REPLY_COMPLETE) {
3948 char c;
3949 bzero((char *)&tmremote, sizeof(struct tm));
3950 s = ftp_reply_str;
3951 while ((c = *s++)) { /* Skip past response code */
3952 if (c == SP) {
3953 flag++;
3954 break;
3955 }
3956 }
3957 }
3958 if (flag) {
3959 debug(F111,"ftp chkmodtime string",s,flag);
3960 if (fts_sto) { /* User gave server time offset? */
3961 char * p;
3962 debug(F110,"ftp chkmodtime offset",fts_sto,0);
3963 ckmakmsg(timebuf,64,s," ",fts_sto,NULL); /* Build delta time */
3964 if ((p = cmcvtdate(timebuf,1))) { /* Apply delta time */
3965 ckstrncpy(timebuf,p,64); /* Convert to MDTM format */
3966 timebuf[8] = timebuf[9]; /* h */
3967 timebuf[9] = timebuf[10]; /* h */
3968 timebuf[10] = timebuf[12]; /* m */
3969 timebuf[11] = timebuf[13]; /* m */
3970 timebuf[12] = timebuf[12]; /* s */
3971 timebuf[13] = timebuf[13]; /* s */
3972 timebuf[14] = NUL;
3973 s = timebuf;
3974 debug(F110,"ftp chkmodtime adjust",s,0);
3975 }
3976 }
3977 if (flag) { /* Convert to struct tm */
3978 char * pat;
3979 int y2kbug = 0; /* Seen in Kerberos 4 FTP servers */
3980 if (!ckstrcmp(s,"191",3,0)) {
3981 pat = "%05d%02d%02d%02d%02d%02d";
3982 y2kbug++;
3983 debug(F110,"ftp chkmodtime Y2K BUG detected",s,0);
3984 } else {
3985 pat = "%04d%02d%02d%02d%02d%02d";
3986 }
3987 if (sscanf(s, /* Parse into struct tm */
3988 pat,
3989 &(tmremote.tm_year),
3990 &(tmremote.tm_mon),
3991 &(tmremote.tm_mday),
3992 &(tmremote.tm_hour),
3993 &(tmremote.tm_min),
3994 &(tmremote.tm_sec)
3995 ) == 6) {
3996 tmremote.tm_year -= (y2kbug ? 19000 : 1900);
3997 debug(F101,"ftp chkmodtime year","",tmremote.tm_year);
3998 tmremote.tm_mon--;
3999
4000 #ifdef DEBUG
4001 debug(F100,"SERVER TIME FOLLOWS:","",0);
4002 dbtime(remote,&tmremote);
4003 #endif /* DEBUG */
4004
4005 if (havedate > -1)
4006 havedate = 1;
4007 }
4008 }
4009 } else { /* Failed */
4010 debug(F101,"ftp chkmodtime ftpcode","",ftpcode);
4011 if (ftpcode == 500 || /* Command unrecognized */
4012 ftpcode == 502 || /* Command not implemented */
4013 ftpcode == 202) /* Command superfluous */
4014 mdtmok = 0; /* Don't ask this server again */
4015 return(-1);
4016 }
4017 if (fc == 0) { /* Compare */
4018 if (havedate == 1) { /* Only if we have both file dates */
4019 /*
4020 Compare with local file's time. We don't use
4021 clock time (time_t) here in case of signed/unsigned
4022 confusion, etc.
4023 */
4024 int xx;
4025 #ifdef COMMENT
4026 #ifdef DEBUG
4027 if (deblog) {
4028 dbtime("LOCAL",tmlocal);
4029 dbtime("REMOT",&tmremote);
4030 }
4031 #endif /* DEBUG */
4032 #endif /* COMMENT */
4033 xx = tmcompare(tmlocal,&tmremote);
4034 debug(F101,"chkmodtime tmcompare","",xx);
4035 return(xx + 1);
4036 }
4037 } else if (ftp_dates) { /* Set */
4038 /*
4039 Here we must convert struct tm to time_t
4040 without applying timezone conversion, for which
4041 there is no portable API. The method is hidden
4042 in mkutime(), defined above.
4043 */
4044 time_t utc;
4045 utc = mkutime(&tmremote);
4046 debug(F111,"ftp chkmodtime mkutime",remote,utc);
4047 if (utc != (time_t)-1)
4048 return(setmodtime(local,utc));
4049 }
4050 return(-1);
4051 }
4052
4053 /* getfile() returns: -1 on error, 0 if file received, 1 if file skipped */
4054
4055 static int
getfile(remote,local,recover,append,pipename,xlate,fcs,rcs)4056 getfile(remote,local,recover,append,pipename,xlate,fcs,rcs)
4057 char * local, * remote, * pipename; int recover, append, xlate, fcs, rcs;
4058 /* getfile */ {
4059 int rc = -1;
4060 ULONG t0, t1;
4061
4062 #ifdef GFTIMER
4063 CKFLOAT sec;
4064 #else
4065 int sec = 0;
4066 #endif /* GFTIMER */
4067 char fullname[CKMAXPATH+1];
4068
4069 debug(F110,"ftp getfile remote A",remote,0);
4070 debug(F110,"ftp getfile local A",local,0);
4071 debug(F110,"ftp getfile pipename",pipename,0);
4072 if (!remote) remote = "";
4073
4074 #ifdef PATTERNS
4075 /* Automatic type switching? */
4076 if (ftp_xfermode == XMODE_A && patterns && get_auto && !forcetype) {
4077 int x;
4078 x = matchname(remote,0,servertype);
4079 debug(F111,"ftp getfile matchname",remote,x);
4080 switch (x) {
4081 case 0: ftp_typ = FTT_ASC; break;
4082 case 1: ftp_typ = tenex ? FTT_TEN : FTT_BIN; break;
4083 default: if (g_ftp_typ > -1) ftp_typ = g_ftp_typ;
4084 }
4085 changetype(ftp_typ,ftp_vbm);
4086 binary = ftp_typ; /* For file-transfer display */
4087 }
4088 #endif /* PATTERNS */
4089
4090 #ifndef NOCSETS
4091 ftp_csx = -1; /* For file-transfer display */
4092 ftp_csl = -1; /* ... */
4093
4094 if (rcs > -1) /* -1 means no translation */
4095 if (ftp_typ == FTT_ASC) /* File type is "ascii"? */
4096 if (fcs < 0) /* File charset not forced? */
4097 fcs = fcharset; /* use prevailing FILE CHARACTER-SET */
4098 if (fcs > -1 && rcs > -1) { /* Set up translation functions */
4099 debug(F110,"ftp getfile","initxlate",0);
4100 initxlate(rcs,fcs); /* NB: opposite order of PUT */
4101 ftp_csx = rcs;
4102 ftp_csl = fcs;
4103 } else
4104 xlate = 0;
4105 #endif /* NOCSETS */
4106
4107 if (!local) local = "";
4108 if (!pipename && !*local)
4109 local = remote;
4110
4111 out2screen = !strcmp(local,"-");
4112
4113 fullname[0] = NUL;
4114 if (pipename) {
4115 ckstrncpy(fullname,pipename,CKMAXPATH+1);
4116 } else {
4117 zfnqfp(local,CKMAXPATH,fullname);
4118 if (!fullname[0])
4119 ckstrncpy(fullname,local,CKMAXPATH+1);
4120 }
4121 if (!out2screen && displa && fdispla) { /* Screen */
4122 ftscreen(SCR_FN,'F',(CK_OFF_T)pktnum,remote);
4123 ftscreen(SCR_AN,0,(CK_OFF_T)0,fullname);
4124 ftscreen(SCR_FS,0,fsize,"");
4125 }
4126 tlog(F110,ftp_typ ? "ftp get BINARY:" : "ftp get TEXT:", remote, 0);
4127 tlog(F110," as",fullname,0);
4128 debug(F111,"ftp getfile size",remote,fsize);
4129 debug(F111,"ftp getfile local",local,out2screen);
4130
4131 ckstrncpy(filnam, pipename ? remote : local, CKMAXPATH);
4132
4133 t0 = gmstimer(); /* Start time */
4134 debug(F111,"ftp getfile t0",remote,t0); /* ^^^ */
4135 rc = recvrequest("RETR",
4136 local,
4137 remote,
4138 append ? "ab" : "wb",
4139 0,
4140 recover,
4141 pipename,
4142 xlate,
4143 fcs,
4144 rcs
4145 );
4146 t1 = gmstimer(); /* End time */
4147 debug(F111,"ftp getfile t1",remote,t1);
4148 debug(F111,"ftp getfile sec",remote,(t1-t0)/1000);
4149 #ifdef GFTIMER
4150 sec = (CKFLOAT)((CKFLOAT)(t1 - t0) / 1000.0); /* Stats */
4151 fpxfsecs = sec; /* (for doxlog()) */
4152 #else
4153 sec = (t1 - t0) / 1000;
4154 xfsecs = (int)sec;
4155 #endif /* GFTIMER */
4156
4157 #ifdef FTP_TIMEOUT
4158 if (ftp_timed_out)
4159 rc = -4;
4160 #endif /* FTP_TIMEOUT */
4161
4162 debug(F111,"ftp recvrequest rc",remote,rc);
4163 if (cancelfile || cancelgroup) {
4164 debug(F111,"ftp get canceled",ckitoa(cancelfile),cancelgroup);
4165 ftscreen(SCR_ST,ST_INT,(CK_OFF_T)0,"");
4166 } else if (rc > 0) {
4167 debug(F111,"ftp get skipped",ckitoa(cancelfile),cancelgroup);
4168 ftscreen(SCR_ST,ST_SKIP,(CK_OFF_T)0,cmarg);
4169 } else if (rc < 0) {
4170 switch (ftpcode) {
4171 case -4: /* Network error */
4172 case -2: /* File error */
4173 ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,ck_errstr());
4174 break;
4175 case -3:
4176 ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,
4177 "Failure to make data connection");
4178 break;
4179 case -1: /* (should be covered above) */
4180 ftscreen(SCR_ST,ST_INT,(CK_OFF_T)0,"");
4181 break;
4182 default:
4183 ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,&ftp_reply_str[4]);
4184 }
4185 } else { /* Tudo bem */
4186 ftscreen(SCR_PT,'Z',(CK_OFF_T)0,"");
4187 if (rc == 0) {
4188 ftscreen(SCR_ST,ST_OK,(CK_OFF_T)0,""); /* For screen */
4189 makestr(&rrfspec,remote); /* For WHERE command */
4190 makestr(&rfspec,fullname);
4191 }
4192 }
4193 if (rc > -1) {
4194 if (ftp_dates) /* If FTP DATES ON... */
4195 if (!pipename && !out2screen) /* and it's a real file */
4196 if (rc < 1 && rc != -3) /* and it wasn't skipped */
4197 if (connected) /* and we still have a connection */
4198 if (zchki(local) > -1) { /* and the file wasn't discarded */
4199 chkmodtime(local,remote,1); /* set local file date */
4200 debug(F110,"ftp get set date",local,0);
4201 }
4202 filcnt++; /* Used by \v(filenum) */
4203 }
4204 #ifdef TLOG
4205 if (tralog) {
4206 if (rc > 0) {
4207 tlog(F100," recovery skipped","",0);
4208 } else if (rc == 0) {
4209 tlog(F101," complete, size", "", fsize);
4210 } else if (cancelfile) {
4211 tlog(F100," canceled by user","",0);
4212 #ifdef FTP_TIMEOUT
4213 } else if (ftp_timed_out) {
4214 tlog(F100," timed out","",0);
4215 #endif /* FTP_TIMEOUT */
4216 } else {
4217 tlog(F110," failed:",ftp_reply_str,0);
4218 }
4219 if (!tlogfmt)
4220 doxlog(what,local,fsize,ftp_typ,rc,"");
4221 }
4222 #endif /* TLOG */
4223 return(rc);
4224 }
4225
4226 /* putfile() returns: -1 on error, >0 if file not selected, 0 on success. */
4227 /* Positive return value is Skip Reason, SKP_xxx, from ckcker.h. */
4228
4229 static int
putfile(cx,local,remote,force,moving,mvto,rnto,srvrn,x_cnv,x_usn,xft,prm,fcs,rcs,flg)4230 putfile(cx,
4231 local,remote,force,moving,mvto,rnto,srvrn,x_cnv,x_usn,xft,prm,fcs,rcs,flg)
4232 char * local, * remote, * mvto, *rnto, *srvrn;
4233 int cx, force, moving, x_cnv, x_usn, xft, fcs, rcs, flg, prm;
4234
4235 /* putfile */ {
4236
4237 char asname[CKMAXPATH+1];
4238 char fullname[CKMAXPATH+1];
4239 int k = -1, x = 0, y = 0, o = -1, rc = 0, nc = 0;
4240 int xlate = 0, restart = 0, mt = -1;
4241 char * s = NULL, * cmd = NULL;
4242 ULONG t0 = 0, t1 = 0; /* Times for stats */
4243 int ofcs = 0, orcs = 0;
4244
4245 #ifdef GFTIMER
4246 CKFLOAT sec = 0.0;
4247 #else
4248 int sec = 0;
4249 #endif /* GFTIMER */
4250 debug(F111,"ftp putfile flg",local,flg);
4251 debug(F110,"ftp putfile srv_renam",srvrn,0);
4252 debug(F101,"ftp putfile fcs","",fcs);
4253 debug(F101,"ftp putfile rcs","",rcs);
4254
4255 ofcs = fcs; /* Save charset args */
4256 orcs = rcs;
4257
4258 sendstart = (CK_OFF_T)0;
4259 restart = flg & PUT_RES;
4260 if (!remote)
4261 remote = "";
4262
4263 /* FTP protocol command to send to server */
4264 cmd = (cx == FTP_APP) ? "APPE" : (x_usn ? "STOU" : "STOR");
4265
4266 if (x_cnv == SET_AUTO) { /* Name conversion is auto */
4267 if (alike) { /* If server & client are alike */
4268 nc = 0; /* no conversion */
4269 } else { /* If they are different */
4270 if (servertype == SYS_UNIX || servertype == SYS_WIN32)
4271 nc = -1; /* only minimal conversions needed */
4272 else /* otherwise */
4273 nc = 1; /* full conversion */
4274 }
4275 } else /* Not auto - do what user said */
4276 nc = x_cnv;
4277
4278 /* If Transfer Mode is Automatic, determine file type */
4279 if (ftp_xfermode == XMODE_A && filepeek && !pipesend) {
4280 if (isdir(local)) { /* If it's a directory */
4281 k = FT_BIN; /* skip the file scan */
4282 } else {
4283 debug(F110,"FTP PUT calling scanfile",local,0);
4284 k = scanfile(local,&o,nscanfile); /* Scan the file */
4285 }
4286 debug(F111,"FTP PUT scanfile",local,k);
4287 if (k > -1 && !forcetype) {
4288 ftp_typ = (k == FT_BIN) ? 1 : 0;
4289 if (xft > -1 && ftp_typ != xft) {
4290 if (flg & PUT_SIM)
4291 tlog(F110,"ftp put SKIP (Type):", local, 0);
4292 return(SKP_TYP);
4293 }
4294 if (ftp_typ == 1 && tenex) /* User said TENEX? */
4295 ftp_typ = FTT_TEN;
4296 }
4297 }
4298 #ifndef NOCSETS
4299 ftp_csx = -1; /* For file-transfer display */
4300 ftp_csl = -1; /* ... */
4301
4302 if (rcs > -1) { /* -1 means no translation */
4303 if (ftp_typ == 0) { /* File type is "ascii"? */
4304 if (fcs < 0) { /* File charset not forced? */
4305 if (k < 0) { /* If we didn't scan */
4306 fcs = fcharset; /* use prevailing FILE CHARACTER-SET */
4307 } else { /* If we did scan, use scan result */
4308 switch (k) {
4309 case FT_TEXT: /* Unknown text */
4310 fcs = fcharset;
4311 break;
4312 case FT_7BIT: /* 7-bit text */
4313 fcs = dcset7;
4314 break;
4315 case FT_8BIT: /* 8-bit text */
4316 fcs = dcset8;
4317 break;
4318 case FT_UTF8: /* UTF-8 */
4319 fcs = FC_UTF8;
4320 break;
4321 case FT_UCS2: /* UCS-2 */
4322 fcs = FC_UCS2;
4323 if (o > -1) /* Input file byte order */
4324 fileorder = o;
4325 break;
4326 default:
4327 rcs = -1;
4328 }
4329 }
4330 }
4331 }
4332 }
4333 if (fcs > -1 && rcs > -1) { /* Set up translation functions */
4334 debug(F110,"ftp putfile","initxlate",0);
4335 initxlate(fcs,rcs);
4336 debug(F111,"ftp putfile rcs",fcsinfo[rcs].keyword,rcs);
4337 xlate = 1;
4338 ftp_csx = rcs;
4339 ftp_csl = fcs;
4340 }
4341 #endif /* NOCSETS */
4342
4343 binary = ftp_typ; /* For file-transfer display */
4344 asname[0] = NUL;
4345
4346 if (recursive) { /* If sending recursively, */
4347 if (!syncdir(local,flg & PUT_SIM)) /* synchronize directories. */
4348 return(-1); /* Don't PUT if it fails. */
4349 else if (isdir(local)) /* It's a directory */
4350 return(0); /* Don't send it! */
4351 }
4352 if (*remote) { /* If an as-name template was given */
4353 #ifndef NOSPL
4354 if (cmd_quoting) { /* and COMMAND QUOTING is ON */
4355 y = CKMAXPATH; /* evaluate it for this file */
4356 s = asname;
4357 zzstring(remote,&s,&y);
4358 } else
4359 #endif /* NOSPL */
4360 ckstrncpy(asname,remote,CKMAXPATH); /* (or take it literally) */
4361 } else { /* No as-name */
4362 nzltor(local,asname,nc,0,CKMAXPATH); /* use local name strip path */
4363 debug(F110,"FTP PUT nzltor",asname,0);
4364 }
4365 /* Preliminary messages and log entries */
4366
4367 fullname[0] = NUL;
4368 zfnqfp(local,CKMAXPATH,fullname);
4369 if (!fullname[0]) ckstrncpy(fullname,local,CKMAXPATH+1);
4370 fullname[CKMAXPATH] = NUL;
4371
4372 if (displa && fdispla) { /* Screen */
4373 ftscreen(SCR_FN,'F',(CK_OFF_T)pktnum,local);
4374 ftscreen(SCR_AN,0,(CK_OFF_T)0,asname);
4375 ftscreen(SCR_FS,0,fsize,"");
4376 }
4377 #ifdef DOUPDATE
4378 if (flg & (PUT_UPD|PUT_DIF)) { /* Date-checking modes... */
4379 mt = chkmodtime(fullname,asname,0);
4380 debug(F111,"ftp putfile chkmodtime",asname,mt);
4381 if (mt == 0 && ((flg & PUT_DIF) == 0)) { /* Local is older */
4382 tlog(F110,"ftp put /update SKIP (Older modtime): ",fullname,0);
4383 /* Skip this one */
4384 ftscreen(SCR_ST,ST_SKIP,(CK_OFF_T)SKP_DAT,fullname);
4385 filcnt++;
4386 return(SKP_DAT);
4387 } else if (mt == 1) { /* Times are equal */
4388 tlog(F110,"ftp put /update SKIP (Equal modtime): ",fullname,0);
4389 ftscreen(SCR_ST,ST_SKIP,(CK_OFF_T)SKP_EQU,fullname); /* Skip it */
4390 filcnt++;
4391 return(SKP_DAT);
4392 }
4393 /* Local file is newer */
4394 tlog(F110,ftp_typ ? "ftp put /update BINARY:" :
4395 "ftp put /update TEXT:", fullname, 0);
4396 } else if (flg & PUT_RES) {
4397 tlog(F110,ftp_typ ? "ftp put /recover BINARY:" :
4398 "ftp put /recover TEXT:", fullname, 0);
4399 } else {
4400 tlog(F110,ftp_typ ? "ftp put BINARY:" : "ftp put TEXT:", fullname, 0);
4401 }
4402 #else
4403 tlog(F110,ftp_typ ? "ftp put BINARY:" : "ftp put TEXT:", fullname, 0);
4404 #endif /* DOUPDATE */
4405 tlog(F110," as",asname,0);
4406
4407 #ifndef NOCSETS
4408 if (xlate) {
4409 debug(F111,"ftp putfile fcs",fcsinfo[fcs].keyword,fcs);
4410 tlog(F110," file character set:",fcsinfo[fcs].keyword,0);
4411 tlog(F110," server character set:",fcsinfo[rcs].keyword,0);
4412 } else if (!ftp_typ) {
4413 tlog(F110," character sets:","no conversion",0);
4414 fcs = ofcs; /* Binary file but we still must */
4415 rcs = orcs; /* translate its name */
4416 }
4417 #endif /* NOCSETS */
4418
4419 /* PUT THE FILE */
4420
4421 t0 = gmstimer(); /* Start time */
4422 if (flg & PUT_SIM) { /* rc > 0 is a skip reason code */
4423 if (flg & (PUT_UPD|PUT_DIF)) { /* (see SKP_xxx in ckcker.h) */
4424 rc = (mt < 0) ? /* Update mode... */
4425 SKP_XNX : /* Remote file doesn't exist */
4426 SKP_XUP; /* Remote file is older */
4427 } else {
4428 rc = SKP_SIM; /* "Would be sent", period. */
4429 }
4430 } else {
4431 rc = sendrequest(cmd,local,asname,xlate,fcs,rcs,restart);
4432 }
4433 t1 = gmstimer(); /* End time */
4434 filcnt++; /* File number */
4435
4436 #ifdef GFTIMER
4437 sec = (CKFLOAT)((CKFLOAT)(t1 - t0) / 1000.0); /* Stats */
4438 fpxfsecs = sec; /* (for doxlog()) */
4439 #else
4440 sec = (t1 - t0) / 1000;
4441 xfsecs = (int)sec;
4442 #endif /* GFTIMER */
4443
4444 debug(F111,"ftp sendrequest rc",local,rc);
4445
4446 if (cancelfile || cancelgroup) {
4447 debug(F111,"ftp put canceled",ckitoa(cancelfile),cancelgroup);
4448 ftscreen(SCR_ST,ST_INT,(CK_OFF_T)0,"");
4449 } else if (rc > 0) {
4450 debug(F101,"ftp put skipped",local,rc);
4451 ftscreen(SCR_ST,ST_SKIP,(CK_OFF_T)rc,fullname);
4452 } else if (rc < 0) {
4453 debug(F111,"ftp put error",local,ftpcode);
4454 ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,&ftp_reply_str[4]);
4455 } else {
4456 debug(F111,"ftp put not canceled",ckitoa(displa),fdispla);
4457 ftscreen(SCR_PT,'Z',(CK_OFF_T)0,"");
4458 debug(F111,"ftp put ST_OK",local,rc);
4459 ftscreen(SCR_ST,ST_OK,(CK_OFF_T)0,"");
4460 debug(F110,"ftp put old sfspec",sfspec,0);
4461 makestr(&sfspec,fullname); /* For WHERE command */
4462 debug(F110,"ftp put new sfspec",sfspec,0);
4463 debug(F110,"ftp put old srfspec",srfspec,0);
4464 makestr(&srfspec,asname);
4465 debug(F110,"ftp put new srfspec",srfspec,0);
4466 }
4467
4468 /* Final log entries */
4469
4470 #ifdef TLOG
4471 if (tralog) {
4472 if (rc > 0) {
4473 if (rc == SKP_XNX)
4474 tlog(F100," /simulate: WOULD BE SENT:","no remote file",0);
4475 else if (rc == SKP_XUP)
4476 tlog(F100," /simulate: WOULD BE SENT:","remote file older",0);
4477 else if (rc == SKP_SIM)
4478 tlog(F100," /simulate: WOULD BE SENT","",0);
4479 else
4480 tlog(F110," skipped:",gskreason(rc),0);
4481 } else if (rc == 0) {
4482 tlog(F101," complete, size", "", fsize);
4483 } else if (cancelfile) {
4484 tlog(F100," canceled by user","",0);
4485 } else {
4486 tlog(F110," failed:",ftp_reply_str,0);
4487 }
4488 if (!tlogfmt)
4489 doxlog(what,local,fsize,ftp_typ,rc,"");
4490 }
4491 #endif /* TLOG */
4492
4493 if (rc < 0) /* PUT did not succeed */
4494 return(-1); /* so done. */
4495
4496 if (flg & PUT_SIM) /* Simulating, skip the rest. */
4497 return(SKP_SIM);
4498
4499 #ifdef UNIX
4500 /* Set permissions too? */
4501
4502 if (prm) { /* Change permissions? */
4503 s = zgperm(local); /* Get perms of local file */
4504 if (!s) s = "";
4505 x = strlen(s);
4506 if (x > 3) s += (x - 3);
4507 if (rdigits(s)) {
4508 ckmakmsg(ftpcmdbuf,FTP_BUFSIZ,s," ",asname,NULL);
4509 x =
4510 ftpcmd("SITE CHMOD",ftpcmdbuf,fcs,rcs,ftp_vbm) == REPLY_COMPLETE;
4511 tlog(F110, x ? " chmod" : " chmod failed",
4512 s,
4513 0
4514 );
4515 if (!x)
4516 return(-1);
4517 }
4518 }
4519 #endif /* UNIX */
4520
4521 /* Disposition of source file */
4522
4523 if (moving) {
4524 x = zdelet(local);
4525 tlog(F110, (x > -1) ?
4526 " deleted" : " failed to delete",
4527 local,
4528 0
4529 );
4530 if (x < 0)
4531 return(-1);
4532 } else if (mvto) {
4533 x = zrename(local,mvto);
4534 tlog(F110, (x > -1) ?
4535 " moved source to" : " failed to move source to",
4536 mvto,
4537 0
4538 );
4539 if (x < 0)
4540 return(-1);
4541 /* ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,mvto); */
4542
4543 } else if (rnto) {
4544 char * s = rnto;
4545 #ifndef NOSPL
4546 int y; /* Pass it thru the evaluator */
4547 extern int cmd_quoting; /* for \v(filename) */
4548 if (cmd_quoting) { /* But only if cmd_quoting is on */
4549 y = CKMAXPATH;
4550 s = (char *)asname;
4551 zzstring(rnto,&s,&y);
4552 s = (char *)asname;
4553 }
4554 #endif /* NOSPL */
4555 if (s) if (*s) {
4556 int x;
4557 x = zrename(local,s);
4558 tlog(F110, (x > -1) ?
4559 " renamed source file to" :
4560 " failed to rename source file to",
4561 s,
4562 0
4563 );
4564 if (x < 0)
4565 return(-1);
4566 /* ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,s); */
4567 }
4568 }
4569
4570 /* Disposition of destination file */
4571
4572 if (srvrn) { /* /SERVER-RENAME: */
4573 char * s = srvrn;
4574 #ifndef NOSPL
4575 int y; /* Pass it thru the evaluator */
4576 extern int cmd_quoting; /* for \v(filename) */
4577 debug(F111,"ftp putfile srvrn",s,1);
4578
4579 if (cmd_quoting) { /* But only if cmd_quoting is on */
4580 y = CKMAXPATH;
4581 s = (char *)fullname; /* We can recycle this buffer now */
4582 zzstring(srvrn,&s,&y);
4583 s = (char *)fullname;
4584 }
4585 #endif /* NOSPL */
4586 debug(F111,"ftp putfile srvrn",s,2);
4587 if (s) if (*s) {
4588 int x;
4589 x = ftp_rename(asname,s);
4590 debug(F111,"ftp putfile ftp_rename",asname,x);
4591 tlog(F110, (x > 0) ?
4592 " renamed destination file to" :
4593 " failed to rename destination file to",
4594 s,
4595 0
4596 );
4597 if (x < 1)
4598 return(-1);
4599 }
4600 }
4601 return(0);
4602 }
4603
4604 /* xxout must only be used for ASCII transfers */
4605 static int
4606 #ifdef CK_ANSIC
xxout(char c)4607 xxout(char c)
4608 #else
4609 xxout(c) char c;
4610 #endif /* CK_ANSIC */
4611 {
4612 #ifndef OS2
4613 #ifndef VMS
4614 #ifndef MAC
4615 #ifndef OSK
4616 /* For Unix, DG, Stratus, Amiga, Gemdos, other */
4617 if (c == '\012') {
4618 if (zzout(dout,(CHAR)'\015') < 0)
4619 return(-1);
4620 ftpsnd.bytes++;
4621 }
4622 #else /* OSK */
4623 if (c == '\015') {
4624 c = '\012';
4625 if (zzout(dout,(CHAR)'\015') < 0)
4626 return(-1);
4627 ftpsnd.bytes++;
4628 }
4629 #endif /* OSK */
4630 #else /* MAC */
4631 if (c == '\015') {
4632 c = '\012';
4633 if (zzout(dout,(CHAR)'\015') < 0)
4634 return(-1);
4635 ftpsnd.bytes++;
4636 }
4637 #endif /* MAC */
4638 #endif /* VMS */
4639 #endif /* OS2 */
4640 if (zzout(dout,(CHAR)c) < 0)
4641 return(-1);
4642 ftpsnd.bytes++;
4643 return(0);
4644 }
4645
4646 static int
4647 #ifdef CK_ANSIC
scrnout(char c)4648 scrnout(char c)
4649 #else
4650 scrnout(c) char c;
4651 #endif /* CK_ANSIC */
4652 {
4653 return(putchar(c));
4654 }
4655
4656 static int
4657 #ifdef CK_ANSIC
pipeout(char c)4658 pipeout(char c)
4659 #else
4660 pipeout(c) char c;
4661 #endif /* CK_ANSIC */
4662 {
4663 return(zmchout(c));
4664 }
4665
4666 static int
ispathsep(c)4667 ispathsep(c) int c; {
4668 switch (servertype) {
4669 case SYS_VMS:
4670 case SYS_TOPS10:
4671 case SYS_TOPS20:
4672 return(((c == ']') || (c == '>') || (c == ':')) ? 1 : 0);
4673 case SYS_OS2:
4674 case SYS_WIN32:
4675 case SYS_DOS:
4676 return(((c == '\\') || (c == '/') || (c == ':')) ? 1 : 0);
4677 case SYS_VOS:
4678 return((c == '>') ? 1 : 0);
4679 default:
4680 return((c == '/') ? 1 : 0);
4681 }
4682 }
4683
4684 static int
iscanceled()4685 iscanceled() {
4686 #ifdef CK_CURSES
4687 extern int ck_repaint();
4688 #endif /* CK_CURSES */
4689 int x, rc = 0;
4690 char c = 0;
4691 if (cancelfile)
4692 return(1);
4693 x = conchk(); /* Any chars waiting at console? */
4694 if (x-- > 0) { /* Yes... */
4695 c = coninc(5); /* Get one */
4696 switch (c) {
4697 case 032: /* Ctrl-X or X */
4698 case 'z':
4699 case 'Z': cancelgroup++; /* fall thru on purpose */
4700 case 030: /* Ctrl-Z or Z */
4701 case 'x':
4702 case 'X': cancelfile++; rc++; break;
4703 #ifdef CK_CURSES
4704 case 'L':
4705 case 'l':
4706 case 014: /* Ctrl-L or L or Ctrl-W */
4707 case 027:
4708 ck_repaint(); /* Refresh screen */
4709 #endif /* CK_CURSES */
4710 }
4711 }
4712 while (x-- > 0) /* Soak up any rest */
4713 c = coninc(1);
4714 return(rc);
4715 }
4716
4717 #ifdef FTP_TIMEOUT
4718 /* fc = 0 for read; 1 for write */
4719 static int
check_data_connection(fd,fc)4720 check_data_connection(fd,fc) int fd, fc; {
4721 int x;
4722 struct timeval tv;
4723 fd_set in, out, err;
4724
4725 if (ftp_timeout < 1L)
4726 return(0);
4727
4728 FD_ZERO(&in);
4729 FD_ZERO(&out);
4730 FD_ZERO(&err);
4731 FD_SET(fd,fc ? &out : &in);
4732 tv.tv_sec = ftp_timeout; /* Time limit */
4733 tv.tv_usec = 0L;
4734
4735 #ifdef INTSELECT
4736 x = select(FD_SETSIZE,(int *)&in,(int *)&out,(int *)&err,&tv);
4737 #else
4738 x = select(FD_SETSIZE,&in,&out,&err,&tv);
4739 #endif /* INTSELECT */
4740
4741 if (x == 0) {
4742 #ifdef EWOULDBLOCK
4743 errno = EWOULDBLOCK;
4744 #else
4745 #ifdef EAGAIN
4746 errno = EAGAIN;
4747 #else
4748 errno = 11;
4749 #endif /* EAGAIN */
4750 #endif /* EWOULDBLOCK */
4751 debug(F100,"ftp check_data_connection TIMOUT","",0);
4752 return(-3);
4753 }
4754 return(0);
4755 }
4756 #endif /* FTP_TIMEOUT */
4757
4758 /* zzsend - used by buffered output macros. */
4759
4760 static int
4761 #ifdef CK_ANSIC
zzsend(int fd,CHAR c)4762 zzsend(int fd, CHAR c)
4763 #else
4764 zzsend(fd,c) int fd; CHAR c;
4765 #endif /* CK_ANSIC */
4766 {
4767 int rc;
4768
4769 debug(F101,"zzsend ucbufsiz","",ucbufsiz);
4770 debug(F101,"zzsend nout","",nout);
4771 debug(F111,"zzsend","secure?",ftpissecure());
4772
4773 if (iscanceled()) /* Check for cancellation */
4774 return(-9);
4775
4776 #ifdef FTP_TIMEOUT
4777 ftp_timed_out = 0;
4778 if (check_data_connection(fd,1) < 0) {
4779 ftp_timed_out = 1;
4780 return(-3);
4781 }
4782 #endif /* FTP_TIMEOUT */
4783
4784 rc = (!ftpissecure()) ?
4785 send(fd, (SENDARG2TYPE)ucbuf, nout, 0) :
4786 secure_putbuf(fd, ucbuf, nout);
4787 ucbuf[nout] = NUL;
4788 nout = 0;
4789 ucbuf[nout++] = c;
4790 spackets++;
4791 pktnum++;
4792 if (rc > -1 && fdispla != XYFD_B) {
4793 spktl = nout;
4794 ftscreen(SCR_PT,'D',(CK_OFF_T)spackets,NULL);
4795 }
4796 return(rc);
4797 }
4798
4799 /* c m d l i n p u t -- Command-line PUT */
4800
4801 int
cmdlinput(stay)4802 cmdlinput(stay) int stay; {
4803 int x, rc = 0, done = 0, good = 0, status = 0;
4804 ULONG t0, t1; /* Times for stats */
4805 #ifdef GFTIMER
4806 CKFLOAT sec;
4807 #else
4808 int sec = 0;
4809 #endif /* GFTIMER */
4810
4811 if (quiet) { /* -q really means quiet */
4812 displa = 0;
4813 fdispla = 0;
4814 } else {
4815 displa = 1;
4816 fdispla = XYFD_B;
4817 }
4818 testing = 0;
4819 out2screen = 0;
4820 dpyactive = 0;
4821 what = W_FTP|W_SEND;
4822
4823 #ifndef NOSPL
4824 cmd_quoting = 0;
4825 #endif /* NOSPL */
4826 sndsrc = nfils;
4827
4828 t0 = gmstimer(); /* Record starting time */
4829
4830 while (!done && !cancelgroup) { /* Loop for all files */
4831
4832 cancelfile = 0;
4833 x = gnfile(); /* Get next file from list(s) */
4834 if (x == 0) /* (see gnfile() comments...) */
4835 x = gnferror;
4836
4837 switch (x) {
4838 case 1: /* File to send */
4839 rc = putfile(FTP_PUT, /* Function (PUT, APPEND) */
4840 filnam, /* Local file to send */
4841 filnam, /* Remote name for file */
4842 forcetype, /* Text/binary mode forced */
4843 0, /* Not moving */
4844 NULL, /* No move-to */
4845 NULL, /* No rename-to */
4846 NULL, /* No server-rename */
4847 ftp_cnv, /* Filename conversion */
4848 0, /* Unique-server-names */
4849 -1, /* All file types */
4850 0, /* No permissions */
4851 -1, /* No character sets */
4852 -1, /* No character sets */
4853 0 /* No update or restart */
4854 );
4855 if (rc > -1) {
4856 good++;
4857 status = 1;
4858 }
4859 if (cancelfile) {
4860 continue; /* Or break? */
4861 }
4862 if (rc < 0) {
4863 ftp_fai++;
4864 }
4865 continue; /* Or break? */
4866
4867 case 0: /* No more files, done */
4868 done++;
4869 continue;
4870
4871 case -2:
4872 case -1:
4873 printf("?%s: file not found - \"%s\"\n",
4874 puterror ? "Fatal" : "Warning",
4875 filnam
4876 );
4877 continue; /* or break? */
4878 case -3:
4879 printf("?Warning access denied - \"%s\"\n", filnam);
4880 continue; /* or break? */
4881 case -5:
4882 printf("?Too many files match\n");
4883 done++;
4884 break;
4885 case -6:
4886 if (good < 1)
4887 printf("?No files selected\n");
4888 done++;
4889 break;
4890 default:
4891 printf("?getnextfile() - unknown failure\n");
4892 done++;
4893 }
4894 }
4895 if (status > 0) {
4896 if (cancelgroup)
4897 status = 0;
4898 else if (cancelfile && good < 1)
4899 status = 0;
4900 }
4901 success = status;
4902 x = success;
4903 if (x > -1) {
4904 lastxfer = W_FTP|W_SEND;
4905 xferstat = success;
4906 }
4907 t1 = gmstimer(); /* End time */
4908 #ifdef GFTIMER
4909 sec = (CKFLOAT)((CKFLOAT)(t1 - t0) / 1000.0); /* Stats */
4910 if (!sec) sec = 0.001;
4911 fptsecs = sec;
4912 #else
4913 sec = (t1 - t0) / 1000;
4914 if (!sec) sec = 1;
4915 #endif /* GFTIMER */
4916 tfcps = (long) (tfc / sec);
4917 tsecs = (int)sec;
4918 lastxfer = W_FTP|W_SEND;
4919 xferstat = success;
4920 if (dpyactive)
4921 ftscreen(status > 0 ? SCR_TC : SCR_CW, 0, (CK_OFF_T)0, "");
4922 if (!stay)
4923 doexit(success ? GOOD_EXIT : BAD_EXIT, -1);
4924 return(success);
4925 }
4926
4927
4928 /* d o f t p p u t -- Parse and execute PUT, MPUT, and APPEND */
4929
4930 int
4931 #ifdef CK_ANSIC
doftpput(int cx,int who)4932 doftpput(int cx, int who) /* who == 1 for ftp, 0 for kermit */
4933 #else
4934 doftpput(cx,who) int cx, who;
4935 #endif /* CK_ANSIC */
4936 {
4937 struct FDB sf, fl, sw, cm;
4938 int n, rc, confirmed = 0, wild = 0, getval = 0, mput = 0, done = 0;
4939 int x_cnv = 0, x_usn = 0, x_prm = 0, putflags = 0, status = 0, good = 0;
4940 char * s, * s2;
4941
4942 int x_csl, x_csr = -1; /* Local and remote charsets */
4943 int x_xla = 0;
4944 int x_recurse = 0;
4945 char c, * p; /* Workers */
4946 #ifdef PUTARRAY
4947 int range[2]; /* Array range */
4948 char ** ap = NULL; /* Array pointer */
4949 int arrayx = -1; /* Array index */
4950 #endif /* PUTARRAY */
4951 ULONG t0 = 0L, t1 = 0L; /* Times for stats */
4952 #ifdef GFTIMER
4953 CKFLOAT sec;
4954 #else
4955 int sec = 0;
4956 #endif /* GFTIMER */
4957
4958 struct stringint pv[SND_MAX+1]; /* Temporary array for switch values */
4959 success = 0; /* Assume failure */
4960 forcetype = 0; /* No /TEXT or /BINARY given yet */
4961 out2screen = 0; /* Not outputting file to screen */
4962 putflags = 0; /* PUT options */
4963 x_cnv = ftp_cnv; /* Filename conversion */
4964 x_usn = ftp_usn; /* Unique server names */
4965 x_prm = ftp_prm; /* Permissions */
4966 if (x_prm == SET_AUTO) /* Permissions AUTO */
4967 x_prm = alike;
4968
4969 #ifndef NOCSETS
4970 x_csr = ftp_csr; /* Inherit global server charset */
4971 x_csl = ftp_csl;
4972 if (x_csl < 0)
4973 x_csl = fcharset;
4974 x_xla = ftp_xla;
4975 #endif /* NOCSETS */
4976
4977 makestr(&filefile,NULL); /* No filename list file yet. */
4978 makestr(&srv_renam,NULL); /* Clear /SERVER-RENAME: */
4979 makestr(&snd_rename,NULL); /* PUT /RENAME */
4980 makestr(&snd_move,NULL); /* PUT /MOVE */
4981 putpath[0] = NUL; /* Initialize for syncdir(). */
4982 puterror = ftp_err; /* Inherit global error action. */
4983 what = W_SEND|W_FTP; /* What we're doing (sending w/FTP) */
4984 asnambuf[0] = NUL; /* Clear as-name buffer */
4985
4986 if (g_ftp_typ > -1) { /* Restore TYPE if saved */
4987 ftp_typ = g_ftp_typ;
4988 /* g_ftp_typ = -1; */
4989 }
4990 for (i = 0; i <= SND_MAX; i++) { /* Initialize switch values */
4991 pv[i].sval = NULL; /* to null pointers */
4992 pv[i].ival = -1; /* and -1 int values */
4993 pv[i].wval = (CK_OFF_T)-1; /* and -1 wide values */
4994 }
4995 if (who == 0) { /* Called with unprefixed command */
4996 switch (cx) {
4997 case XXRSEN: pv[SND_RES].ival = 1; break;
4998 case XXCSEN: pv[SND_CMD].ival = 1; break;
4999 case XXMOVE: pv[SND_DEL].ival = 1; break;
5000 case XXMMOVE: pv[SND_DEL].ival = 1; /* fall thru */
5001 case XXMSE: mput++; break;
5002 }
5003 } else {
5004 if (cx == FTP_REP)
5005 pv[SND_RES].ival = 1;
5006 if (cx == FTP_MPU)
5007 mput++;
5008 }
5009 cmfdbi(&sw, /* First FDB - command switches */
5010 _CMKEY, /* fcode */
5011 "Filename, or switch", /* hlpmsg */
5012 "", /* default */
5013 "", /* addtl string data */
5014 nputswi, /* addtl numeric data 1: tbl size */
5015 4, /* addtl numeric data 2: 4 = cmswi */
5016 xxstring, /* Processing function */
5017 putswi, /* Keyword table */
5018 &sf /* Pointer to next FDB */
5019 );
5020 cmfdbi(&fl, /* 3rd FDB - local filespec */
5021 _CMFLD, /* fcode */
5022 "", /* hlpmsg */
5023 "", /* default */
5024 "", /* addtl string data */
5025 0, /* addtl numeric data 1 */
5026 0, /* addtl numeric data 2 */
5027 xxstring,
5028 NULL,
5029 &cm
5030 );
5031 cmfdbi(&cm, /* 4th FDB - Confirmation */
5032 _CMCFM, /* fcode */
5033 "", /* hlpmsg */
5034 "", /* default */
5035 "", /* addtl string data */
5036 0, /* addtl numeric data 1 */
5037 0, /* addtl numeric data 2 */
5038 NULL,
5039 NULL,
5040 NULL
5041 );
5042
5043 again:
5044 cmfdbi(&sf, /* 2nd FDB - file to send */
5045 _CMIFI, /* fcode */
5046 "", /* hlpmsg */
5047 "", /* default */
5048 "", /* addtl string data */
5049 /* 0 = parse files, 1 = parse files or dirs, 2 = skip symlinks */
5050 nolinks | x_recurse, /* addtl numeric data 1 */
5051 0, /* dirflg 0 means "not dirs only" */
5052 xxstring,
5053 NULL,
5054 #ifdef COMMENT
5055 mput ? &cm : &fl
5056 #else
5057 &fl
5058 #endif /* COMMENT */
5059 );
5060
5061 while (1) { /* Parse zero or more switches */
5062 x = cmfdb(&sw); /* Parse something */
5063 debug(F101,"ftp put cmfdb A","",x);
5064 debug(F101,"ftp put fcode A","",cmresult.fcode);
5065 if (x < 0) /* Error */
5066 goto xputx; /* or reparse needed */
5067 if (cmresult.fcode != _CMKEY) /* Break out of loop if not a switch */
5068 break;
5069 c = cmgbrk(); /* Get break character */
5070 getval = (c == ':' || c == '='); /* to see how they ended the switch */
5071 if (getval && !(cmresult.kflags & CM_ARG)) {
5072 printf("?This switch does not take arguments\n");
5073 x = -9;
5074 goto xputx;
5075 }
5076 if (!getval && (cmgkwflgs() & CM_ARG)) {
5077 printf("?This switch requires an argument\n");
5078 x = -9;
5079 goto xputx;
5080 }
5081 n = cmresult.nresult; /* Numeric result = switch value */
5082 debug(F101,"ftp put switch","",n);
5083
5084 switch (n) { /* Process the switch */
5085 case SND_AFT: /* Send /AFTER:date-time */
5086 case SND_BEF: /* Send /BEFORE:date-time */
5087 case SND_NAF: /* Send /NOT-AFTER:date-time */
5088 case SND_NBE: /* Send /NOT-BEFORE:date-time */
5089 if (!getval) break;
5090 if ((x = cmdate("File date-time","",&s,0,xxstring)) < 0) {
5091 if (x == -3) {
5092 printf("?Date-time required\n");
5093 x = -9;
5094 }
5095 goto xputx;
5096 }
5097 pv[n].ival = 1;
5098 makestr(&(pv[n].sval),s);
5099 break;
5100
5101 case SND_ASN: /* /AS-NAME: */
5102 debug(F101,"ftp put /as-name getval","",getval);
5103 if (!getval) break;
5104 if ((x = cmfld("Name to send under","",&s,NULL)) < 0) {
5105 if (x == -3) {
5106 printf("?name required\n");
5107 x = -9;
5108 }
5109 goto xputx;
5110 }
5111 makestr(&(pv[n].sval),brstrip(s));
5112 debug(F110,"ftp put /as-name 1",pv[n].sval,0);
5113 if (pv[n].sval) pv[n].ival = 1;
5114 break;
5115
5116 #ifdef PUTARRAY
5117 case SND_ARR: /* /ARRAY */
5118 if (!getval) break;
5119 ap = NULL;
5120 if ((x = cmfld("Array name (a single letter will do)",
5121 "",
5122 &s,
5123 NULL
5124 )) < 0) {
5125 if (x == -3)
5126 break;
5127 else
5128 return(x);
5129 }
5130 if ((x = arraybounds(s,&(range[0]),&(range[1]))) < 0) {
5131 printf("?Bad array: %s\n",s);
5132 return(-9);
5133 }
5134 if (!(ap = a_ptr[x])) {
5135 printf("?No such array: %s\n",s);
5136 return(-9);
5137 }
5138 pv[n].ival = 1;
5139 pv[SND_CMD].ival = 0; /* Undo any conflicting ones... */
5140 pv[SND_RES].ival = 0;
5141 pv[SND_FIL].ival = 0;
5142 arrayx = x;
5143 break;
5144 #endif /* PUTARRAY */
5145
5146 case SND_BIN: /* /BINARY */
5147 case SND_TXT: /* /TEXT or /ASCII */
5148 case SND_TEN: /* /TENEX */
5149 pv[SND_BIN].ival = 0;
5150 pv[SND_TXT].ival = 0;
5151 pv[SND_TEN].ival = 0;
5152 pv[n].ival = 1;
5153 break;
5154
5155 #ifdef PUTPIPE
5156 case SND_CMD: /* These take no args */
5157 if (nopush) {
5158 printf("?Sorry, system command access is disabled\n");
5159 x = -9;
5160 goto xputx;
5161 }
5162 #ifdef PIPESEND
5163 else if (sndfilter) {
5164 printf("?Sorry, no PUT /COMMAND when SEND FILTER selected\n");
5165 x = -9;
5166 goto xputx;
5167 }
5168 #endif /* PIPESEND */
5169 sw.hlpmsg = "Command, or switch"; /* Change help message */
5170 pv[n].ival = 1; /* Just set the flag */
5171 pv[SND_ARR].ival = 0;
5172 break;
5173 #endif /* PUTPIPE */
5174
5175 #ifdef CKSYMLINK
5176 case SND_LNK:
5177 nolinks = 0;
5178 goto again; /* Because CMIFI params changed... */
5179 case SND_NLK:
5180 nolinks = 2;
5181 goto again;
5182 #endif /* CKSYMLINK */
5183
5184 #ifdef FTP_RESTART
5185 case SND_RES: /* /RECOVER (resend) */
5186 pv[SND_ARR].ival = 0; /* fall thru on purpose... */
5187 #endif /* FTP_RESTART */
5188
5189 case SND_NOB:
5190 case SND_DEL: /* /DELETE */
5191 case SND_SHH: /* /QUIET */
5192 case SND_UPD: /* /UPDATE */
5193 case SND_SIM: /* /UPDATE */
5194 case SND_USN: /* /UNIQUE */
5195 pv[n].ival = 1; /* Just set the flag */
5196 break;
5197
5198 case SND_REC: /* /RECURSIVE */
5199 recursive = 2; /* Must be set before cmifi() */
5200 x_recurse = 1;
5201 goto again; /* Because CMIFI params changed... */
5202 break;
5203
5204 #ifdef UNIXOROSK
5205 case SND_DOT: /* /DOTFILES */
5206 matchdot = 1;
5207 break;
5208 case SND_NOD: /* /NODOTFILES */
5209 matchdot = 0;
5210 break;
5211 #endif /* UNIXOROSK */
5212
5213 case SND_ERR: /* /ERROR-ACTION */
5214 if ((x = cmkey(qorp,2,"","",xxstring)) < 0)
5215 goto xputx;
5216 pv[n].ival = x;
5217 break;
5218
5219 case SND_EXC: /* Excludes */
5220 if (!getval) break;
5221 if ((x = cmfld("Pattern","",&s,xxstring)) < 0) {
5222 if (x == -3) {
5223 printf("?Pattern required\n");
5224 x = -9;
5225 }
5226 goto xputx;
5227 }
5228 if (s) if (!*s) s = NULL;
5229 makestr(&(pv[n].sval),s);
5230 if (pv[n].sval)
5231 pv[n].ival = 1;
5232 break;
5233
5234 case SND_PRM: /* /PERMISSIONS */
5235 if (!getval)
5236 x = 1;
5237 else if ((x = cmkey(onoff,2,"","on",xxstring)) < 0)
5238 goto xputx;
5239 pv[SND_PRM].ival = x;
5240 break;
5241
5242 #ifdef PIPESEND
5243 case SND_FLT: /* /FILTER */
5244 debug(F101,"ftp put /filter getval","",getval);
5245 if (!getval) break;
5246 if ((x = cmfld("Filter program to send through","",&s,NULL)) < 0) {
5247 if (x == -3)
5248 s = "";
5249 else
5250 goto xputx;
5251 }
5252 if (*s) s = brstrip(s);
5253 y = strlen(s);
5254 for (x = 0; x < y; x++) { /* Make sure they included "\v(...)" */
5255 if (s[x] != '\\') continue;
5256 if (s[x+1] == 'v') break;
5257 }
5258 if (x == y) {
5259 printf(
5260 "?Filter must contain a replacement variable for filename.\n"
5261 );
5262 x = -9;
5263 goto xputx;
5264 }
5265 if (s) if (!*s) s = NULL;
5266 makestr(&(pv[n].sval),s);
5267 if (pv[n].sval)
5268 pv[n].ival = 1;
5269 break;
5270 #endif /* PIPESEND */
5271
5272 case SND_NAM: /* /FILENAMES */
5273 if (!getval) break;
5274 if ((x = cmkey(fntab,nfntab,"","automatic",xxstring)) < 0)
5275 goto xputx;
5276 debug(F101,"ftp put /filenames","",x);
5277 pv[n].ival = x;
5278 break;
5279
5280 case SND_SMA: /* Smaller / larger than */
5281 case SND_LAR: {
5282 CK_OFF_T y;
5283 if (!getval) break;
5284 if ((x = cmnumw("Size in bytes","0",10,&y,xxstring)) < 0)
5285 goto xputx;
5286 pv[n].wval = y;
5287 break;
5288 }
5289 case SND_FIL: /* Name of file containing filenames */
5290 if (!getval) break;
5291 if ((x = cmifi("Name of file containing list of filenames",
5292 "",&s,&y,xxstring)) < 0) {
5293 if (x == -3) {
5294 printf("?Filename required\n");
5295 x = -9;
5296 }
5297 goto xputx;
5298 } else if (y && iswild(s)) {
5299 printf("?Wildcards not allowed\n");
5300 x = -9;
5301 goto xputx;
5302 }
5303 if (s) if (!*s) s = NULL;
5304 makestr(&(pv[n].sval),s);
5305 if (pv[n].sval) {
5306 pv[n].ival = 1;
5307 pv[SND_ARR].ival = 0;
5308 } else {
5309 pv[n].ival = 0;
5310 }
5311 mput = 0;
5312 break;
5313
5314 case SND_MOV: /* MOVE after */
5315 case SND_REN: /* RENAME after */
5316 case SND_SRN: { /* SERVER-RENAME after */
5317 char * m = "";
5318 switch (n) {
5319 case SND_MOV:
5320 m = "device and/or directory for source file after sending";
5321 break;
5322 case SND_REN:
5323 m = "new name for source file after sending";
5324 break;
5325 case SND_SRN:
5326 m = "new name for destination file after sending";
5327 break;
5328 }
5329 if (!getval) break;
5330 if ((x = cmfld(m, "", &s, n == SND_MOV ? xxstring : NULL)) < 0) {
5331 if (x == -3) {
5332 printf("%s\n", n == SND_MOV ?
5333 "?Destination required" :
5334 "?New name required"
5335 );
5336 x = -9;
5337 }
5338 goto xputx;
5339 }
5340 if (s) if (!*s) s = NULL;
5341 makestr(&(pv[n].sval),s ? brstrip(s) : NULL);
5342 pv[n].ival = (pv[n].sval) ? 1 : 0;
5343 break;
5344 }
5345 case SND_STA: /* Starting position (= PSEND) */
5346 if (!getval) break;
5347 if ((x = cmnum("0-based position","0",10,&y,xxstring)) < 0)
5348 goto xputx;
5349 pv[n].ival = y;
5350 break;
5351
5352 case SND_TYP: /* /TYPE */
5353 if (!getval) break;
5354 if ((x = cmkey(txtbin,3,"","all",xxstring)) < 0)
5355 goto xputx;
5356 pv[n].ival = (x == 2) ? -1 : x;
5357 break;
5358
5359 #ifndef NOCSETS
5360 case SND_CSL: /* Local character set */
5361 case SND_CSR: /* Remote (server) charset */
5362 if ((x = cmkey(fcstab,nfilc,"","",xxstring)) < 0) {
5363 return((x == -3) ? -2 : x);
5364 }
5365 if (n == SND_CSL)
5366 x_csl = x;
5367 else
5368 x_csr = x;
5369 x_xla = 1; /* Overrides global OFF setting */
5370 break;
5371
5372 case SND_XPA: /* Transparent */
5373 x_xla = 0;
5374 x_csr = -1;
5375 x_csl = -1;
5376 break;
5377 #endif /* NOCSETS */
5378 }
5379 }
5380 #ifdef PIPESEND
5381 if (pv[SND_RES].ival > 0) { /* /RECOVER */
5382 if (sndfilter || pv[SND_FLT].ival > 0) {
5383 printf("?Sorry, no /RECOVER or /START if SEND FILTER selected\n");
5384 x = -9;
5385 goto xputx;
5386 }
5387 if (sfttab[0] > 0 && sfttab[SFT_REST] == 0)
5388 printf("WARNING: Server says it doesn't support REST.\n");
5389 }
5390 #endif /* PIPESEND */
5391
5392 cmarg = "";
5393 cmarg2 = asnambuf;
5394 line[0] = NUL;
5395 s = line;
5396 wild = 0;
5397
5398 switch (cmresult.fcode) { /* How did we get out of switch loop */
5399 case _CMIFI: /* Input filename */
5400 if (pv[SND_FIL].ival > 0) {
5401 printf("?You may not give a PUT filespec and a /LISTFILE\n");
5402 x = -9;
5403 goto xputx;
5404 }
5405 ckstrncpy(line,cmresult.sresult,LINBUFSIZ); /* Name */
5406 if (pv[SND_ARR].ival > 0)
5407 ckstrncpy(asnambuf,line,CKMAXPATH);
5408 else
5409 wild = cmresult.nresult; /* Wild flag */
5410 debug(F111,"ftp put wild",line,wild);
5411 if (!wild && !recursive && !mput)
5412 nolinks = 0;
5413 break;
5414 case _CMFLD: /* Field */
5415 /* Only allowed with /COMMAND and /ARRAY */
5416 if (pv[SND_FIL].ival > 0) {
5417 printf("?You may not give a PUT filespec and a /LISTFILE\n");
5418 x = -9;
5419 goto xputx;
5420 }
5421 /* For MPUT it's OK to have filespecs that don't match any files */
5422 if (mput)
5423 break;
5424 if (pv[SND_CMD].ival < 1 && pv[SND_ARR].ival < 1) {
5425 #ifdef CKROOT
5426 if (ckrooterr)
5427 printf("?Off limits: %s\n",cmresult.sresult);
5428 else
5429 #endif /* CKROOT */
5430 printf("?%s - \"%s\"\n",
5431 iswild(cmresult.sresult) ?
5432 "No files match" : "File not found",
5433 cmresult.sresult
5434 );
5435 x = -9;
5436 goto xputx;
5437 }
5438 ckstrncpy(line,cmresult.sresult,LINBUFSIZ);
5439 if (pv[SND_ARR].ival > 0)
5440 ckstrncpy(asnambuf,line,CKMAXPATH);
5441 break;
5442 case _CMCFM: /* Confirmation */
5443 confirmed = 1;
5444 break;
5445 default:
5446 printf("?Unexpected function code: %d\n",cmresult.fcode);
5447 x = -9;
5448 goto xputx;
5449 }
5450 debug(F110,"ftp put string",s,0);
5451 debug(F101,"ftp put confirmed","",confirmed);
5452
5453 /* Save and change protocol and transfer mode */
5454 /* Global values are restored in main parse loop */
5455
5456 g_displa = fdispla;
5457 if (ftp_dis > -1)
5458 fdispla = ftp_dis;
5459 g_skipbup = skipbup;
5460
5461 if (pv[SND_NOB].ival > -1) { /* /NOBACKUP (skip backup file) */
5462 g_skipbup = skipbup;
5463 skipbup = 1;
5464 }
5465 if (pv[SND_TYP].ival > -1) { /* /TYPE */
5466 xfiletype = pv[SND_TYP].ival;
5467 if (xfiletype == 2)
5468 xfiletype = -1;
5469 }
5470 if (pv[SND_BIN].ival > 0) { /* /BINARY really means binary... */
5471 forcetype = 1; /* So skip file scan */
5472 ftp_typ = FTT_BIN; /* Set binary */
5473 } else if (pv[SND_TXT].ival > 0) { /* Similarly for /TEXT... */
5474 forcetype = 1;
5475 ftp_typ = FTT_ASC;
5476 } else if (pv[SND_TEN].ival > 0) { /* and /TENEX*/
5477 forcetype = 1;
5478 ftp_typ = FTT_TEN;
5479 } else if (ftp_cmdlin && ftp_xfermode == XMODE_M) {
5480 forcetype = 1;
5481 ftp_typ = binary;
5482 g_ftp_typ = binary;
5483 }
5484
5485 #ifdef PIPESEND
5486 if (pv[SND_CMD].ival > 0) { /* /COMMAND - strip any braces */
5487 debug(F110,"PUT /COMMAND before stripping",s,0);
5488 s = brstrip(s);
5489 debug(F110,"PUT /COMMAND after stripping",s,0);
5490 if (!*s) {
5491 printf("?Sorry, a command to send from is required\n");
5492 x = -9;
5493 goto xputx;
5494 }
5495 cmarg = s;
5496 }
5497 #endif /* PIPESEND */
5498
5499 /* Set up /MOVE and /RENAME */
5500
5501 if (pv[SND_DEL].ival > 0 &&
5502 (pv[SND_MOV].ival > 0 || pv[SND_REN].ival > 0)) {
5503 printf("?Sorry, /DELETE conflicts with /MOVE or /RENAME\n");
5504 x = -9;
5505 goto xputx;
5506 }
5507 #ifdef CK_TMPDIR
5508 if (pv[SND_MOV].ival > 0) {
5509 int len;
5510 char * p = pv[SND_MOV].sval;
5511 len = strlen(p);
5512 if (!isdir(p)) { /* Check directory */
5513 #ifdef CK_MKDIR
5514 char * s = NULL;
5515 s = (char *)malloc(len + 4);
5516 if (s) {
5517 strcpy(s,p); /* safe */
5518 #ifdef datageneral
5519 if (s[len-1] != ':') { s[len++] = ':'; s[len] = NUL; }
5520 #else
5521 if (s[len-1] != '/') { s[len++] = '/'; s[len] = NUL; }
5522 #endif /* datageneral */
5523 s[len++] = 'X';
5524 s[len] = NUL;
5525 #ifdef NOMKDIR
5526 x = -1;
5527 #else
5528 x = zmkdir(s);
5529 #endif /* NOMKDIR */
5530 free(s);
5531 if (x < 0) {
5532 printf("?Can't create \"%s\"\n",p);
5533 x = -9;
5534 goto xputx;
5535 }
5536 }
5537 #else
5538 printf("?Directory \"%s\" not found\n",p);
5539 x = -9;
5540 goto xputx;
5541 #endif /* CK_MKDIR */
5542 }
5543 makestr(&snd_move,p);
5544 }
5545 #endif /* CK_TMPDIR */
5546
5547 if (pv[SND_REN].ival > 0) { /* /RENAME */
5548 char * p = pv[SND_REN].sval;
5549 if (!p) p = "";
5550 if (!*p) {
5551 printf("?New name required for /RENAME\n");
5552 x = -9;
5553 goto xputx;
5554 }
5555 p = brstrip(p);
5556 #ifndef NOSPL
5557 /* If name given is wild, rename string must contain variables */
5558 if (wild) {
5559 char * s = tmpbuf;
5560 x = TMPBUFSIZ;
5561 zzstring(p,&s,&x);
5562 if (!strcmp(tmpbuf,p)) {
5563 printf(
5564 "?/RENAME for file group must contain variables such as \\v(filename)\n"
5565 );
5566 x = -9;
5567 goto xputx;
5568 }
5569 }
5570 #endif /* NOSPL */
5571 makestr(&snd_rename,p);
5572 debug(F110,"FTP snd_rename",snd_rename,0);
5573 }
5574 if (pv[SND_SRN].ival > 0) { /* /SERVER-RENAME */
5575 char * p = pv[SND_SRN].sval;
5576 if (!p) p = "";
5577 if (!*p) {
5578 printf("?New name required for /SERVER-RENAME\n");
5579 x = -9;
5580 goto xputx;
5581 }
5582 p = brstrip(p);
5583 #ifndef NOSPL
5584 if (wild) {
5585 char * s = tmpbuf;
5586 x = TMPBUFSIZ;
5587 zzstring(p,&s,&x);
5588 if (!strcmp(tmpbuf,p)) {
5589 printf(
5590 "?/SERVER-RENAME for file group must contain variables such as \\v(filename)\n"
5591 );
5592 x = -9;
5593 goto xputx;
5594 }
5595 }
5596 #endif /* NOSPL */
5597 makestr(&srv_renam,p);
5598 debug(F110,"ftp put srv_renam",srv_renam,0);
5599 }
5600 if (!confirmed) { /* CR not typed yet, get more fields */
5601 char * lp;
5602 if (mput) { /* MPUT or MMOVE */
5603 nfils = 0; /* We already have the first one */
5604 #ifndef NOMSEND
5605 if (cmresult.fcode == _CMIFI) {
5606 /* First filespec is valid */
5607 msfiles[nfils++] = line; /* Store pointer */
5608 lp = line + (int)strlen(line) + 1; /* Point past it */
5609 debug(F111,"ftp put mput",msfiles[nfils-1],nfils-1);
5610 } else {
5611 /* First filespec matches no files */
5612 debug(F110,"ftp put mput skipping first filespec",
5613 cmresult.sresult,
5614 0
5615 );
5616 lp = line;
5617 }
5618 /* Parse a filespec, a "field", or confirmation */
5619
5620 cmfdbi(&sf, /* 1st FDB - file to send */
5621 _CMIFI, /* fcode */
5622 "", /* hlpmsg */
5623 "", /* default */
5624 "", /* addtl string data */
5625 nolinks | x_recurse, /* addtl numeric data 1 */
5626 0, /* dirflg 0 means "not dirs only" */
5627 xxstring,
5628 NULL,
5629 &fl
5630 );
5631 cmfdbi(&fl, /* 2nd FDB - local filespec */
5632 _CMFLD, /* fcode */
5633 "", /* hlpmsg */
5634 "", /* default */
5635 "", /* addtl string data */
5636 0, /* addtl numeric data 1 */
5637 0, /* addtl numeric data 2 */
5638 xxstring,
5639 NULL,
5640 &cm
5641 );
5642 cmfdbi(&cm, /* 3rd FDB - Confirmation */
5643 _CMCFM, /* fcode */
5644 "",
5645 "",
5646 "",
5647 0,
5648 0,
5649 NULL,
5650 NULL,
5651 NULL
5652 );
5653
5654 while (!confirmed) { /* Get more filenames */
5655 x = cmfdb(&sf); /* Parse something */
5656 debug(F101,"ftp put cmfdb B","",x);
5657 debug(F101,"ftp put fcode B","",cmresult.fcode);
5658 if (x < 0) /* Error */
5659 goto xputx; /* or reparse needed */
5660 switch (cmresult.fcode) {
5661 case _CMCFM: /* End of command */
5662 confirmed++;
5663 if (nfils < 1) {
5664 debug(F100,"ftp put mput no files match","",0);
5665 printf("?No files match MPUT list\n");
5666 x = -9;
5667 goto xputx;
5668 }
5669 break;
5670 case _CMFLD: /* No match */
5671 debug(F110,"ftp put mput skipping",cmresult.sresult,0);
5672 continue;
5673 case _CMIFI: /* Good match */
5674 s = cmresult.sresult;
5675 msfiles[nfils++] = lp; /* Got one, count, point to it, */
5676 p = lp; /* remember pointer, */
5677 while ((*lp++ = *s++)) /* and copy it into buffer */
5678 if (lp > (line + LINBUFSIZ)) { /* Avoid memory leak */
5679 printf("?MPUT list too long\n");
5680 line[0] = NUL;
5681 x = -9;
5682 goto xputx;
5683 }
5684 debug(F111,"ftp put mput adding",msfiles[nfils-1],nfils-1);
5685 if (nfils == 1) /* Take care of \v(filespec) */
5686 fspec[0] = NUL;
5687 #ifdef ZFNQFP
5688 zfnqfp(p,TMPBUFSIZ,tmpbuf);
5689 p = tmpbuf;
5690 #endif /* ZFNQFP */
5691 if (((int)strlen(fspec) + (int)strlen(p) + 1) < fspeclen) {
5692 strcat(fspec,p); /* safe */
5693 strcat(fspec," "); /* safe */
5694 } else {
5695 #ifdef COMMENT
5696 printf("WARNING - \\v(filespec) buffer overflow\n");
5697 #else
5698 debug(F101,"doxput filespec buffer overflow","",0);
5699 #endif /* COMMENT */
5700 }
5701 }
5702 }
5703 #endif /* NOMSEND */
5704 } else { /* Regular PUT */
5705 nfils = -1;
5706 if ((x = cmtxt(wild ?
5707 "\nOptional as-name template containing replacement variables \
5708 like \\v(filename)" :
5709 "Optional name to send it with",
5710 "",&p,NULL)) < 0)
5711 goto xputx;
5712
5713 if (p) if (!*p) p = NULL;
5714 p = brstrip(p);
5715
5716 if (p && *p) {
5717 makestr(&(pv[SND_ASN].sval),p);
5718 if (pv[SND_ASN].sval)
5719 pv[SND_ASN].ival = 1;
5720 debug(F110,"ftp put /as-name 2",pv[SND_ASN].sval,0);
5721 }
5722 }
5723 }
5724 /* Set cmarg2 from as-name, however we got it. */
5725
5726 CHECKCONN();
5727 if (pv[SND_ASN].ival > 0 && pv[SND_ASN].sval && !asnambuf[0]) {
5728 char * p;
5729 p = brstrip(pv[SND_ASN].sval);
5730 ckstrncpy(asnambuf,p,CKMAXPATH+1);
5731 }
5732 debug(F110,"ftp put asnambuf",asnambuf,0);
5733
5734 if (pv[SND_FIL].ival > 0) {
5735 if (confirmed) {
5736 if (zopeni(ZMFILE,pv[SND_FIL].sval) < 1) {
5737 debug(F110,"ftp put can't open",pv[SND_FIL].sval,0);
5738 printf("?Failure to open %s\n",pv[SND_FIL].sval);
5739 x = -9;
5740 goto xputx;
5741 }
5742 makestr(&filefile,pv[SND_FIL].sval); /* Open, remember name */
5743 debug(F110,"ftp PUT /LISTFILE opened",filefile,0);
5744 wild = 1;
5745 }
5746 }
5747 if (confirmed && !line[0] && !filefile) {
5748 #ifndef NOMSEND
5749 if (filehead) { /* OK if we have a SEND-LIST */
5750 nfils = filesinlist;
5751 sndsrc = nfils; /* Like MSEND */
5752 addlist = 1; /* But using a different list... */
5753 filenext = filehead;
5754 goto doput;
5755 }
5756 #endif /* NOMSEND */
5757 printf("?Filename required but not given\n");
5758 x = -9;
5759 goto xputx;
5760 }
5761 #ifndef NOMSEND
5762 addlist = 0; /* Don't use SEND-LIST. */
5763 #endif /* NOMSEND */
5764
5765 if (mput) { /* MPUT (rather than PUT) */
5766 #ifndef NOMSEND
5767 cmlist = msfiles; /* List of filespecs */
5768 sndsrc = nfils; /* rather filespec and as-name */
5769 #endif /* NOMSEND */
5770 pipesend = 0;
5771 } else if (filefile) { /* File contains list of filenames */
5772 s = "";
5773 cmarg = "";
5774 line[0] = NUL;
5775 nfils = 1;
5776 sndsrc = 1;
5777
5778 } else if (pv[SND_ARR].ival < 1 && pv[SND_CMD].ival < 1) {
5779
5780 /* Not MSEND, MMOVE, /LIST, or /ARRAY */
5781 nfils = sndsrc = -1;
5782 if (!wild) {
5783 if (zchki(s) < 0) {
5784 printf("?Read access denied - \"%s\"\n", s);
5785 x = -9;
5786 goto xputx;
5787 }
5788 }
5789 if (s != line) /* We might already have done this. */
5790 ckstrncpy(line,s,LINBUFSIZ); /* Copy of string just parsed. */
5791 #ifdef DEBUG
5792 else
5793 debug(F110,"doxput line=s",line,0);
5794 #endif /* DEBUG */
5795 cmarg = line; /* File to send */
5796 }
5797 #ifndef NOMSEND
5798 zfnqfp(cmarg,fspeclen,fspec); /* Get full name */
5799 #endif /* NOMSEND */
5800
5801 if (!mput) { /* For all but MPUT... */
5802 #ifdef PIPESEND
5803 if (pv[SND_CMD].ival > 0) /* /COMMAND sets pipesend flag */
5804 pipesend = 1;
5805 debug(F101,"ftp put /COMMAND pipesend","",pipesend);
5806 if (pipesend && filefile) {
5807 printf("?Invalid switch combination\n");
5808 x = -9;
5809 goto xputx;
5810 }
5811 #endif /* PIPESEND */
5812
5813 #ifndef NOSPL
5814 /* If as-name given and filespec is wild, as-name must contain variables */
5815 if ((wild || mput) && asnambuf[0]) {
5816 char * s = tmpbuf;
5817 x = TMPBUFSIZ;
5818 zzstring(asnambuf,&s,&x);
5819 if (!strcmp(tmpbuf,asnambuf)) {
5820 printf(
5821 "?As-name for file group must contain variables such as \\v(filename)\n"
5822 );
5823 x = -9;
5824 goto xputx;
5825 }
5826 }
5827 #endif /* NOSPL */
5828 }
5829
5830 doput:
5831
5832 if (pv[SND_SHH].ival > 0) { /* SEND /QUIET... */
5833 fdispla = 0;
5834 debug(F101,"ftp put display","",fdispla);
5835 } else {
5836 displa = 1;
5837 if (ftp_deb)
5838 fdispla = XYFD_B;
5839 }
5840
5841 #ifdef PUTARRAY /* SEND /ARRAY... */
5842 if (pv[SND_ARR].ival > 0) {
5843 if (!ap) { x = -2; goto xputx; } /* (shouldn't happen) */
5844 if (range[0] == -1) /* If low end of range not specified */
5845 range[0] = 1; /* default to 1 */
5846 if (range[1] == -1) /* If high not specified */
5847 range[1] = a_dim[arrayx]; /* default to size of array */
5848 if ((range[0] < 0) || /* Check range */
5849 (range[0] > a_dim[arrayx]) ||
5850 (range[1] < range[0]) ||
5851 (range[1] > a_dim[arrayx])) {
5852 printf("?Bad array range - [%d:%d]\n",range[0],range[1]);
5853 x = -9;
5854 goto xputx;
5855 }
5856 sndarray = ap; /* Array pointer */
5857 sndxin = arrayx; /* Array index */
5858 sndxlo = range[0]; /* Array range */
5859 sndxhi = range[1];
5860 sndxnam[7] = (char)((sndxin == 1) ? 64 : sndxin + ARRAYBASE);
5861 if (!asnambuf[0])
5862 ckstrncpy(asnambuf,sndxnam,CKMAXPATH);
5863 cmarg = "";
5864 }
5865 #endif /* PUTARRAY */
5866
5867 moving = 0;
5868
5869 if (pv[SND_ARR].ival < 1) { /* File selection & disposition... */
5870 if (pv[SND_DEL].ival > 0) /* /DELETE was specified */
5871 moving = 1;
5872 if (pv[SND_AFT].ival > 0) /* Copy SEND criteria */
5873 ckstrncpy(sndafter,pv[SND_AFT].sval,19);
5874 if (pv[SND_BEF].ival > 0)
5875 ckstrncpy(sndbefore,pv[SND_BEF].sval,19);
5876 if (pv[SND_NAF].ival > 0)
5877 ckstrncpy(sndnafter,pv[SND_NAF].sval,19);
5878 if (pv[SND_NBE].ival > 0)
5879 ckstrncpy(sndnbefore,pv[SND_NBE].sval,19);
5880 if (pv[SND_EXC].ival > 0)
5881 makelist(pv[SND_EXC].sval,sndexcept,NSNDEXCEPT);
5882 if (pv[SND_SMA].ival > -1)
5883 sndsmaller = pv[SND_SMA].wval;
5884 if (pv[SND_LAR].ival > -1)
5885 sndlarger = pv[SND_LAR].wval;
5886 if (pv[SND_NAM].ival > -1)
5887 x_cnv = pv[SND_NAM].ival;
5888 if (pv[SND_USN].ival > -1)
5889 x_usn = pv[SND_USN].ival;
5890 if (pv[SND_ERR].ival > -1)
5891 puterror = pv[SND_ERR].ival;
5892
5893 #ifdef DOUPDATE
5894 if (pv[SND_UPD].ival > 0) {
5895 if (x_usn) {
5896 printf("?Conflicting switches: /UPDATE /UNIQUE\n");
5897 x = -9;
5898 goto xputx;
5899 }
5900 putflags |= PUT_UPD;
5901 ftp_dates |= 2;
5902 }
5903 #ifdef COMMENT
5904 /* This works but it's useless, maybe dangerous */
5905 if (pv[SND_DIF].ival > 0) {
5906 if (x_usn) {
5907 printf("?Conflicting switches: /DATES-DIFFER /UNIQUE\n");
5908 x = -9;
5909 goto xputx;
5910 }
5911 putflags |= PUT_DIF;
5912 ftp_dates |= 2;
5913 }
5914 #endif /* COMMENT */
5915 #endif /* DOUPDATE */
5916
5917 if (pv[SND_SIM].ival > 0)
5918 putflags |= PUT_SIM;
5919
5920 if (pv[SND_PRM].ival > -1) {
5921 #ifdef UNIX
5922 if (x_usn) {
5923 printf("?Conflicting switches: /PERMISSIONS /UNIQUE\n");
5924 x = -9;
5925 goto xputx;
5926 }
5927 x_prm = pv[SND_PRM].ival;
5928 #else /* UNIX */
5929 printf("?/PERMISSIONS switch is not supported\n");
5930 #endif /* UNIX */
5931 }
5932 #ifdef FTP_RESTART
5933 if (pv[SND_RES].ival > 0) {
5934 if (!sizeok) {
5935 printf("?PUT /RESTART can't be used because SIZE disabled.\n");
5936 x = -9;
5937 goto xputx;
5938 }
5939 if (x_usn || putflags) {
5940 printf("?Conflicting switches: /RECOVER %s\n",
5941 x_usn && putflags ? "/UNIQUE /UPDATE" :
5942 (x_usn ? "/UNIQUE" : "/UPDATE")
5943 );
5944 x = -9;
5945 goto xputx;
5946 }
5947 #ifndef NOCSETS
5948 if (x_xla &&
5949 (x_csl == FC_UCS2 ||
5950 x_csl == FC_UTF8 ||
5951 x_csr == FC_UCS2 ||
5952 x_csr == FC_UTF8)) {
5953 printf("?/RECOVER can not be used with Unicode translation\n");
5954 x = -9;
5955 goto xputx;
5956 }
5957 #endif /* NOCSETS */
5958 putflags = PUT_RES;
5959 }
5960 #endif /* FTP_RESTART */
5961 }
5962 debug(F101,"ftp PUT restart","",putflags & PUT_RES);
5963 debug(F101,"ftp PUT update","",putflags & PUT_UPD);
5964
5965 #ifdef PIPESEND
5966 if (pv[SND_FLT].ival > 0) { /* Have SEND FILTER? */
5967 if (!pv[SND_FLT].sval) {
5968 sndfilter = NULL;
5969 } else {
5970 sndfilter = (char *) malloc((int) strlen(pv[SND_FLT].sval) + 1);
5971 if (sndfilter) strcpy(sndfilter,pv[SND_FLT].sval); /* safe */
5972 }
5973 debug(F110,"ftp put /FILTER", sndfilter, 0);
5974 }
5975 if (sndfilter || pipesend) /* No /UPDATE or /RESTART */
5976 if (putflags) /* with pipes or filters */
5977 putflags = 0;
5978 #endif /* PIPESEND */
5979
5980 tfc = (CK_OFF_T)0; /* Initialize stats and counters */
5981 filcnt = 0;
5982 pktnum = 0;
5983 spackets = 0L;
5984
5985 if (wild) /* (is this necessary?) */
5986 cx = FTP_MPU;
5987
5988 t0 = gmstimer(); /* Record starting time */
5989
5990 done = 0; /* Loop control */
5991 cancelgroup = 0;
5992
5993 cdlevel = 0;
5994 cdsimlvl = 0;
5995 while (!done && !cancelgroup) { /* Loop for all files */
5996 /* or until canceled. */
5997 #ifdef FTP_PROXY
5998 /*
5999 If we are using a proxy, we don't use the local file list;
6000 instead we use the list on the remote machine which we want
6001 sent to someone else, and we use remglob() to get the names.
6002 But in that case we shouldn't even be executing this routine;
6003 see ftp_mput().
6004 */
6005 #endif /* FTP_PROXY */
6006
6007 cancelfile = 0;
6008 x = gnfile(); /* Get next file from list(s) */
6009
6010 if (x == 0) /* (see gnfile() comments...) */
6011 x = gnferror;
6012 debug(F111,"FTP PUT gnfile",filnam,x);
6013 debug(F111,"FTP PUT binary",filnam,binary);
6014
6015 switch (x) {
6016 case 1: /* File to send */
6017 s2 = asnambuf;
6018 #ifndef NOSPL
6019 if (asnambuf[0]) { /* As-name */
6020 int n; char *p; /* to be evaluated... */
6021 n = TMPBUFSIZ;
6022 p = tmpbuf;
6023 zzstring(asnambuf,&p,&n);
6024 s2 = tmpbuf;
6025 debug(F110,"ftp put asname",s2,0);
6026 }
6027 #endif /* NOSPL */
6028 rc = putfile(cx, /* Function (PUT, APPEND) */
6029 filnam, s2, /* Name to send, as-name */
6030 forcetype, moving, /* Parameters from switches... */
6031 snd_move, snd_rename, srv_renam,
6032 x_cnv, x_usn, xfiletype, x_prm,
6033 #ifndef NOCSETS
6034 x_csl, (!x_xla ? -1 : x_csr),
6035 #else
6036 -1, -1,
6037 #endif /* NOCSETS */
6038 putflags
6039 );
6040 debug(F111,"ftp put putfile rc",filnam,rc);
6041 debug(F111,"ftp put putfile cancelfile",filnam,cancelfile);
6042 debug(F111,"ftp put putfile cancelgroup",filnam,cancelgroup);
6043 if (rc > -1) {
6044 good++;
6045 status = 1;
6046 }
6047 if (cancelfile)
6048 continue;
6049 if (rc < 0) {
6050 ftp_fai++;
6051 if (puterror) {
6052 status = 0;
6053 printf("?Fatal upload error: %s\n",filnam);
6054 done++;
6055 }
6056 }
6057 continue;
6058 case 0: /* No more files, done */
6059 done++;
6060 continue;
6061 case -1:
6062 printf("?%s: file not found - \"%s\"\n",
6063 puterror ? "Fatal" : "Warning",
6064 filnam
6065 );
6066 if (puterror) {
6067 status = 0;
6068 done++;
6069 break;
6070 }
6071 continue;
6072 case -2:
6073 if (puterror) {
6074 printf("?Fatal: file not found - \"%s\"\n", filnam);
6075 status = 0;
6076 done++;
6077 break;
6078 }
6079 continue; /* Not readable, keep going */
6080 case -3:
6081 if (puterror) {
6082 printf("?Fatal: Read access denied - \"%s\"\n", filnam);
6083 status = 0;
6084 done++;
6085 break;
6086 }
6087 printf("?Warning access denied - \"%s\"\n", filnam);
6088 continue;
6089 #ifdef COMMENT
6090 case -4: /* Canceled */
6091 done++;
6092 break;
6093 #endif /* COMMENT */
6094 case -5:
6095 printf("?Too many files match\n");
6096 done++;
6097 break;
6098 case -6:
6099 if (good < 1)
6100 printf("?No files selected\n");
6101 done++;
6102 break;
6103 default:
6104 printf("?getnextfile() - unknown failure\n");
6105 done++;
6106 }
6107 }
6108 if (cdlevel > 0) {
6109 while (cdlevel--) {
6110 if (cdsimlvl) {
6111 cdsimlvl--;
6112 } else if (!doftpcdup())
6113 break;
6114 }
6115 }
6116 if (status > 0) {
6117 if (cancelgroup)
6118 status = 0;
6119 else if (cancelfile && good < 1)
6120 status = 0;
6121 }
6122 success = status;
6123 x = success;
6124
6125 xputx:
6126 if (x > -1) {
6127 #ifdef GFTIMER
6128 t1 = gmstimer(); /* End time */
6129 sec = (CKFLOAT)((CKFLOAT)(t1 - t0) / 1000.0); /* Stats */
6130 if (!sec) sec = 0.001;
6131 fptsecs = sec;
6132 #else
6133 sec = (t1 - t0) / 1000;
6134 if (!sec) sec = 1;
6135 #endif /* GFTIMER */
6136 tfcps = (long) (tfc / sec);
6137 tsecs = (int)sec;
6138 lastxfer = W_FTP|W_SEND;
6139 xferstat = success;
6140 if (dpyactive)
6141 ftscreen(status > 0 ? SCR_TC : SCR_CW, 0, (CK_OFF_T)0, "");
6142 }
6143 for (i = 0; i <= SND_MAX; i++) { /* Free malloc'd memory */
6144 if (pv[i].sval)
6145 free(pv[i].sval);
6146 }
6147 ftreset(); /* Undo switch effects */
6148 dpyactive = 0;
6149 return(x);
6150 }
6151
6152
6153 static char ** mgetlist = NULL; /* For MGET */
6154 static int mgetn = 0, mgetx = 0;
6155 static char xtmpbuf[4096];
6156
6157 /*
6158 c m d l i n g e t
6159
6160 Get files specified by -g command-line option.
6161 File list is set up in cmlist[] by ckuusy.c; nfils is length of list.
6162 */
6163 int
cmdlinget(stay)6164 cmdlinget(stay) int stay; {
6165 int i, x, rc = 0, done = 0, good = 0, status = 0, append = 0;
6166 int lcs = -1, rcs = -1, xlate = 0;
6167 int first = 1;
6168 int mget = 1;
6169 int nc;
6170 char * s, * s2, * s3;
6171 ULONG t0, t1; /* Times for stats */
6172 #ifdef GFTIMER
6173 CKFLOAT sec;
6174 #else
6175 int sec = 0;
6176 #endif /* GFTIMER */
6177
6178 if (quiet) { /* -q really means quiet */
6179 displa = 0;
6180 fdispla = 0;
6181 } else {
6182 displa = 1;
6183 fdispla = XYFD_B;
6184 }
6185 testing = 0;
6186 dpyactive = 0;
6187 out2screen = 0;
6188 what = W_FTP|W_RECV;
6189 mgetmethod = 0;
6190 mgetforced = 0;
6191
6192 havetype = 0;
6193 havesize = (CK_OFF_T)-1;
6194 makestr(&havemdtm,NULL);
6195
6196 if (ftp_fnc < 0)
6197 ftp_fnc = fncact;
6198
6199 #ifndef NOSPL
6200 cmd_quoting = 0;
6201 #endif /* NOSPL */
6202 debug(F101,"ftp cmdlinget nfils","",nfils);
6203
6204 if (ftp_cnv == CNV_AUTO) { /* Name conversion is auto */
6205 if (alike) { /* If server & client are alike */
6206 nc = 0; /* no conversion */
6207 } else { /* If they are different */
6208 if (servertype == SYS_UNIX || servertype == SYS_WIN32)
6209 nc = -1; /* only minimal conversions needed */
6210 else /* otherwise */
6211 nc = 1; /* full conversion */
6212 }
6213 } else /* Not auto - do what user said */
6214 nc = ftp_cnv;
6215
6216 if (nfils < 1)
6217 doexit(BAD_EXIT,-1);
6218
6219 t0 = gmstimer(); /* Starting time for this batch */
6220
6221 #ifndef NOCSETS
6222 if (xlate) { /* SET FTP CHARACTER-SET-TRANSLATION */
6223 lcs = ftp_csl; /* Local charset */
6224 if (lcs < 0) lcs = fcharset;
6225 if (lcs < 0) xlate = 0;
6226 }
6227 if (xlate) { /* Still ON? */
6228 rcs = ftp_csx; /* Remote (Server) charset */
6229 if (rcs < 0) rcs = ftp_csr;
6230 if (rcs < 0) xlate = 0;
6231 }
6232 #endif /* NOCSETS */
6233 /*
6234 If we have only one file and it is a directory, then we ask for a
6235 listing of its contents, rather than retrieving the directory file
6236 itself. This is what (e.g.) Netscape does.
6237 */
6238 if (nfils == 1) {
6239 if (doftpcwd((char *)cmlist[mgetx],-1)) {
6240 /* If we can CD to it, it must be a directory */
6241 if (recursive) {
6242 cmlist[mgetx] = "*";
6243 } else {
6244 status =
6245 (recvrequest("LIST","-","","wb",0,0,NULL,xlate,lcs,rcs)==0);
6246 done = 1;
6247 }
6248 }
6249 }
6250 /*
6251 The following is to work around UNIX servers which, when given a command
6252 like "NLST path/blah" (not wild) returns the basename without the path.
6253 */
6254 if (!done && servertype == SYS_UNIX && nfils == 1) {
6255 mget = iswild(cmlist[mgetx]);
6256 }
6257 if (!mget && !done) { /* Invoked by command-line FTP URL */
6258 if (ftp_deb)
6259 printf("DOING GET...\n");
6260 done++;
6261 cancelfile = 0; /* This file not canceled yet */
6262 s = cmlist[mgetx];
6263 rc = 0; /* Initial return code */
6264 fsize = (CK_OFF_T)-1;
6265 if (sizeok) {
6266 x = ftpcmd("SIZE",s,lcs,rcs,ftp_vbm); /* Get remote file's size */
6267 if (x == REPLY_COMPLETE)
6268 fsize = ckatofs(&ftp_reply_str[4]);
6269 }
6270 ckstrncpy(filnam,s,CKMAXPATH); /* For \v(filename) */
6271 debug(F111,"ftp cmdlinget filnam",filnam,fsize);
6272
6273 nzrtol(s,tmpbuf,nc,0,CKMAXPATH); /* Strip path and maybe convert */
6274 s2 = tmpbuf;
6275
6276 /* If local file already exists, take collision action */
6277
6278 if (zchki(s2) > -1) {
6279 switch (ftp_fnc) {
6280 case XYFX_A: /* Append */
6281 append = 1;
6282 break;
6283 case XYFX_R: /* Rename */
6284 case XYFX_B: { /* Backup */
6285 char * p = NULL;
6286 int x = -1;
6287 znewn(s2,&p); /* Make unique name */
6288 debug(F110,"ftp cmdlinget znewn",p,0);
6289 if (ftp_fnc == XYFX_B) { /* Backup existing file */
6290 x = zrename(s2,p);
6291 debug(F111,"ftp cmdlinget backup zrename",p,x);
6292 } else { /* Rename incoming file */
6293 x = ckstrncpy(tmpbuf,p,CKMAXPATH+1);
6294 s2 = tmpbuf;
6295 debug(F111,"ftp cmdlinget rename incoming",p,x);
6296 }
6297 if (x < 0) {
6298 printf("?Backup/Rename failed\n");
6299 return(success = 0);
6300 }
6301 break;
6302 }
6303 case XYFX_D: /* Discard */
6304 ftscreen(SCR_FN,'F',(CK_OFF_T)0,s);
6305 ftscreen(SCR_ST,ST_SKIP,(CK_OFF_T)SKP_NAM,s);
6306 tlog(F100," refused: name","",0);
6307 debug(F110,"ftp cmdlinget skip name",s2,0);
6308 goto xclget;
6309
6310 case XYFX_X: /* Overwrite */
6311 case XYFX_U: /* Update (already handled above) */
6312 case XYFX_M: /* ditto */
6313 break;
6314 }
6315 }
6316 rc = getfile(s, /* Remote name */
6317 s2, /* Local name */
6318 0, /* Recover/Restart */
6319 append, /* Append */
6320 NULL, /* Pipename */
6321 0, /* Translate charsets */
6322 -1, /* File charset (none) */
6323 -1 /* Server charset (none) */
6324 );
6325 debug(F111,"ftp cmdlinget rc",s,rc);
6326 debug(F111,"ftp cmdlinget cancelfile",s,cancelfile);
6327 debug(F111,"ftp cmdlinget cancelgroup",s,cancelgroup);
6328
6329 if (rc < 0 && haveurl && s[0] == '/') /* URL failed - try again */
6330 rc = getfile(&s[1], /* Remote name without leading '/' */
6331 s2, /* Local name */
6332 0, /* Recover/Restart */
6333 append, /* Append */
6334 NULL, /* Pipename */
6335 0, /* Translate charsets */
6336 -1, /* File charset (none) */
6337 -1 /* Server charset (none) */
6338 );
6339 if (rc > -1) {
6340 good++;
6341 status = 1;
6342 }
6343 if (cancelfile)
6344 goto xclget;
6345 if (rc < 0) {
6346 ftp_fai++;
6347 #ifdef FTP_TIMEOUT
6348 if (ftp_timed_out)
6349 status = 0;
6350 #endif /* FTP_TIMEOUT */
6351 if (geterror) {
6352 status = 0;
6353 done++;
6354 }
6355 }
6356 }
6357 if (ftp_deb && !done)
6358 printf("DOING MGET...\n");
6359 while (!done && !cancelgroup) {
6360 cancelfile = 0; /* This file not canceled yet */
6361 s = (char *)remote_files(first,(CHAR *)cmlist[mgetx],NULL,0);
6362 if (!s) s = "";
6363 if (!*s) {
6364 first = 1;
6365 mgetx++;
6366 if (mgetx < nfils)
6367 s = (char *)remote_files(first,(CHAR *)cmlist[mgetx],NULL,0);
6368 else
6369 s = NULL;
6370 debug(F111,"ftp cmdlinget remote_files B",s,0);
6371 if (!s) {
6372 done = 1;
6373 break;
6374 }
6375 }
6376 /*
6377 The semantics of NLST are ill-defined. Suppose we have just sent
6378 NLST /path/[a-z]*. Most servers send back names like /path/foo,
6379 /path/bar, etc. But some send back only foo and bar, and subsequent
6380 RETR commands based on the pathless names are not going to work.
6381 */
6382 if (servertype == SYS_UNIX && !ckstrchr(s,'/')) {
6383 if ((s3 = ckstrrchr(cmlist[mgetx],'/'))) {
6384 int len, left = 4096;
6385 char * tmp = xtmpbuf;
6386 len = s3 - cmlist[mgetx] + 1;
6387 ckstrncpy(tmp,cmlist[mgetx],left);
6388 tmp += len;
6389 left -= len;
6390 ckstrncpy(tmp,s,left);
6391 s = xtmpbuf;
6392 debug(F111,"ftp cmdlinget remote_files X",s,0);
6393 }
6394 }
6395 first = 0; /* Not first any more */
6396
6397 debug(F111,"ftp cmdlinget havetype",s,havetype);
6398 if (havetype > 0 && havetype != FTYP_FILE) { /* Server says not file */
6399 debug(F110,"ftp cmdlinget not-a-file",s,0);
6400 continue;
6401 }
6402 rc = 0; /* Initial return code */
6403 if (havesize > (CK_OFF_T)-1) { /* Already have file size? */
6404 fsize = havesize;
6405 } else { /* No - must ask server */
6406 /*
6407 Prior to sending the NLST command we necessarily put the
6408 server into ASCII mode. We must now put it back into the
6409 the requested mode so the upcoming SIZE command returns
6410 right kind of size; this is especially important for
6411 GET /RECOVER; otherwise the server returns the "ASCII" size
6412 of the file, rather than its true size.
6413 */
6414 changetype(ftp_typ,0); /* Change to requested type */
6415 fsize = (CK_OFF_T)-1;
6416 if (sizeok) {
6417 x = ftpcmd("SIZE",s,lcs,rcs,ftp_vbm);
6418 if (x == REPLY_COMPLETE)
6419 fsize = ckatofs(&ftp_reply_str[4]);
6420 }
6421 }
6422 ckstrncpy(filnam,s,CKMAXPATH); /* For \v(filename) */
6423 debug(F111,"ftp cmdlinget filnam",filnam,fsize);
6424
6425 nzrtol(s,tmpbuf,nc,0,CKMAXPATH); /* Strip path and maybe convert */
6426 s2 = tmpbuf;
6427
6428 /* If local file already exists, take collision action */
6429
6430 if (zchki(s2) > -1) {
6431 switch (ftp_fnc) {
6432 case XYFX_A: /* Append */
6433 append = 1;
6434 break;
6435 case XYFX_R: /* Rename */
6436 case XYFX_B: { /* Backup */
6437 char * p = NULL;
6438 int x = -1;
6439 znewn(s2,&p); /* Make unique name */
6440 debug(F110,"ftp cmdlinget znewn",p,0);
6441 if (ftp_fnc == XYFX_B) { /* Backup existing file */
6442 x = zrename(s2,p);
6443 debug(F111,"ftp cmdlinget backup zrename",p,x);
6444 } else { /* Rename incoming file */
6445 x = ckstrncpy(tmpbuf,p,CKMAXPATH+1);
6446 s2 = tmpbuf;
6447 debug(F111,"ftp cmdlinget rename incoming",p,x);
6448 }
6449 if (x < 0) {
6450 printf("?Backup/Rename failed\n");
6451 return(success = 0);
6452 }
6453 break;
6454 }
6455 case XYFX_D: /* Discard */
6456 ftscreen(SCR_FN,'F',(CK_OFF_T)0,s);
6457 ftscreen(SCR_ST,ST_SKIP,(CK_OFF_T)SKP_NAM,s);
6458 tlog(F100," refused: name","",0);
6459 debug(F110,"ftp cmdlinget skip name",s2,0);
6460 continue;
6461 case XYFX_X: /* Overwrite */
6462 case XYFX_U: /* Update (already handled above) */
6463 case XYFX_M: /* ditto */
6464 break;
6465 }
6466 }
6467 /* ^^^ ADD CHARSET STUFF HERE ^^^ */
6468 rc = getfile(s, /* Remote name */
6469 s2, /* Local name */
6470 0, /* Recover/Restart */
6471 append, /* Append */
6472 NULL, /* Pipename */
6473 0, /* Translate charsets */
6474 -1, /* File charset (none) */
6475 -1 /* Server charset (none) */
6476 );
6477 debug(F111,"ftp cmdlinget rc",s,rc);
6478 debug(F111,"ftp cmdlinget cancelfile",s,cancelfile);
6479 debug(F111,"ftp cmdlinget cancelgroup",s,cancelgroup);
6480
6481 if (rc > -1) {
6482 good++;
6483 status = 1;
6484 }
6485 if (cancelfile)
6486 continue;
6487 if (rc < 0) {
6488 ftp_fai++;
6489 #ifdef FTP_TIMEOUT
6490 if (ftp_timed_out)
6491 status = 0;
6492 #endif /* FTP_TIMEOUT */
6493 if (geterror) {
6494 status = 0;
6495 done++;
6496 }
6497 }
6498 }
6499
6500 xclget:
6501 if (cancelgroup)
6502 mlsreset();
6503 if (status > 0) {
6504 if (cancelgroup)
6505 status = 0;
6506 else if (cancelfile && good < 1)
6507 status = 0;
6508 }
6509 success = status;
6510
6511 #ifdef GFTIMER
6512 t1 = gmstimer(); /* End time */
6513 sec = (CKFLOAT)((CKFLOAT)(t1 - t0) / 1000.0); /* Stats */
6514 if (!sec) sec = 0.001;
6515 fptsecs = sec;
6516 #else
6517 sec = (t1 - t0) / 1000;
6518 if (!sec) sec = 1;
6519 #endif /* GFTIMER */
6520
6521 tfcps = (long) (tfc / sec);
6522 tsecs = (int)sec;
6523 lastxfer = W_FTP|W_RECV;
6524 xferstat = success;
6525 if (dpyactive)
6526 ftscreen(status > 0 ? SCR_TC : SCR_CW, 0, (CK_OFF_T)0, "");
6527 if (!stay)
6528 doexit(success ? GOOD_EXIT : BAD_EXIT, -1);
6529 return(success);
6530 }
6531
6532 /* d o f t p g e t -- Parse and execute GET, MGET, MDELETE, ... */
6533
6534 /*
6535 Note: if we wanted to implement /AFTER:, /BEFORE:, etc, we could use
6536 zstrdat() to convert to UTC-based time_t. But it doesn't make sense from
6537 the user-interface perspective, since the server's directory listings show
6538 its own local times and since we don't know what timezone it's in, there's
6539 no way to reconcile our local times with the server's.
6540 */
6541 int
doftpget(cx,who)6542 doftpget(cx,who) int cx, who; { /* who == 1 for ftp, 0 for kermit */
6543 struct FDB fl, sw, cm;
6544 int i, n, rc, getval = 0, mget = 0, done = 0, pipesave = 0;
6545 int x_cnv = 0, x_prm = 0, restart = 0, status = 0, good = 0;
6546 int x_fnc = 0, first = 0, skipthis = 0, append = 0, selected = 0;
6547 int renaming = 0, mdel = 0, listfile = 0, updating = 0, getone = 0;
6548 int moving = 0, deleting = 0, toscreen = 0, haspath = 0;
6549 int gotsize = 0;
6550 int matchdot = 0;
6551 CK_OFF_T getlarger = (CK_OFF_T)-1;
6552 CK_OFF_T getsmaller = (CK_OFF_T)-1;
6553 char * msg, * s, * s2, * nam, * pipename = NULL, * pn = NULL;
6554 char * src = "", * local = "";
6555 char * pat = "";
6556
6557 int x_csl = -1, x_csr = -1; /* Local and remote charsets */
6558 int x_xla = 0;
6559 char c; /* Worker char */
6560 ULONG t0 = 0L, t1; /* Times for stats */
6561 #ifdef GFTIMER
6562 CKFLOAT sec;
6563 #else
6564 int sec = 0;
6565 #endif /* GFTIMER */
6566
6567 struct stringint pv[SND_MAX+1]; /* Temporary array for switch values */
6568
6569 success = 0; /* Assume failure */
6570 forcetype = 0; /* No /TEXT or /BINARY given yet */
6571 restart = 0; /* No restart yet */
6572 out2screen = 0; /* No TO-SCREEN switch given yet */
6573 mgetmethod = 0; /* No NLST or MLSD switch yet */
6574 mgetforced = 0;
6575
6576 g_displa = fdispla;
6577 if (ftp_dis > -1)
6578 fdispla = ftp_dis;
6579
6580 x_cnv = ftp_cnv; /* Filename conversion */
6581 if (x_cnv == CNV_AUTO) { /* Name conversion is auto */
6582 if (alike) { /* If server & client are alike */
6583 x_cnv = 0; /* no conversion */
6584 } else { /* If they are different */
6585 if (servertype == SYS_UNIX || servertype == SYS_WIN32)
6586 x_cnv = -1; /* only minimal conversions needed */
6587 else /* otherwise */
6588 x_cnv = 1; /* full conversion */
6589 }
6590 } else /* Not auto - do what user said */
6591 x_cnv = ftp_cnv;
6592
6593 x_prm = ftp_prm; /* Permissions */
6594 if (x_prm == SET_AUTO) /* Permissions AUTO */
6595 x_prm = alike;
6596
6597 #ifndef NOCSETS
6598 x_csr = ftp_csr; /* Inherit global server charset */
6599 x_csl = ftp_csl; /* Inherit global local charset */
6600 if (x_csl < 0) /* If none, use current */
6601 x_csl = fcharset; /* file character-set. */
6602 x_xla = ftp_xla; /* Translation On/Off */
6603 #endif /* NOCSETS */
6604
6605 geterror = ftp_err; /* Inherit global error action. */
6606 asnambuf[0] = NUL; /* No as-name yet. */
6607 pipesave = pipesend;
6608 pipesend = 0;
6609
6610 havetype = 0;
6611 havesize = (CK_OFF_T)-1;
6612 makestr(&havemdtm,NULL);
6613
6614 if (g_ftp_typ > -1) { /* Restore TYPE if saved */
6615 ftp_typ = g_ftp_typ;
6616 /* g_ftp_typ = -1; */
6617 }
6618 for (i = 0; i <= SND_MAX; i++) { /* Initialize switch values */
6619 pv[i].sval = NULL; /* to null pointers */
6620 pv[i].ival = -1; /* and -1 int values */
6621 pv[i].wval = (CK_OFF_T)-1; /* and -1 wide values */
6622 }
6623 zclose(ZMFILE); /* In case it was left open */
6624
6625 x_fnc = ftp_fnc > -1 ? ftp_fnc : fncact; /* Filename collision action */
6626
6627 if (fp_nml) { /* Reset /NAMELIST */
6628 if (fp_nml != stdout)
6629 fclose(fp_nml);
6630 fp_nml = NULL;
6631 }
6632 makestr(&ftp_nml,NULL);
6633
6634 /* Initialize list of remote filespecs */
6635
6636 if (!mgetlist) {
6637 mgetlist = (char **)malloc(MGETMAX * sizeof(char *));
6638 if (!mgetlist) {
6639 printf("?Memory allocation failure - MGET list\n");
6640 return(-9);
6641 }
6642 for (i = 0; i < MGETMAX; i++)
6643 mgetlist[i] = NULL;
6644 }
6645 mgetn = 0; /* Number of mget arguments */
6646 mgetx = 0; /* Current arg */
6647
6648 if (who == 0) { /* Called with unprefixed command */
6649 if (cx == XXGET || cx == XXREGET || cx == XXRETR)
6650 getone++;
6651 switch (cx) {
6652 case XXREGET: pv[SND_RES].ival = 1; break;
6653 case XXRETR: pv[SND_DEL].ival = 1; break;
6654 case XXGET:
6655 case XXMGET: mget++; break;
6656 }
6657 } else { /* FTP command */
6658 if (cx == FTP_GET || cx == FTP_RGE)
6659 getone++;
6660 switch (cx) {
6661 case FTP_DEL: /* (fall thru on purpose) */
6662 case FTP_MDE: mdel++; /* (ditto) */
6663 case FTP_GET: /* (ditto) */
6664 case FTP_MGE: mget++; break;
6665 case FTP_RGE: pv[SND_RES].ival = 1; break;
6666 }
6667 }
6668 cmfdbi(&sw, /* First FDB - command switches */
6669 _CMKEY, /* fcode */
6670 "Remote filename;\n or switch", /* hlpmsg */
6671 "", /* default */
6672 "", /* addtl string data */
6673 mdel ? ndelswi : ngetswi, /* addtl numeric data 1: tbl size */
6674 4, /* addtl numeric data 2: 4 = cmswi */
6675 xxstring, /* Processing function */
6676 mdel ? delswi : getswi, /* Keyword table */
6677 &fl /* Pointer to next FDB */
6678 );
6679 cmfdbi(&fl, /* 2nd FDB - remote filename */
6680 _CMFLD, /* fcode */
6681 "", /* hlpmsg */
6682 "", /* default */
6683 "", /* addtl string data */
6684 0, /* addtl numeric data 1 */
6685 0, /* addtl numeric data 2 */
6686 xxstring,
6687 NULL,
6688 &cm
6689 );
6690 cmfdbi(&cm, /* 3rd FDB - Confirmation */
6691 _CMCFM, /* fcode */
6692 "", /* hlpmsg */
6693 "", /* default */
6694 "", /* addtl string data */
6695 0, /* addtl numeric data 1 */
6696 0, /* addtl numeric data 2 */
6697 NULL,
6698 NULL,
6699 NULL
6700 );
6701
6702 while (1) { /* Parse 0 or more switches */
6703 x = cmfdb(&sw); /* Parse something */
6704 debug(F101,"ftp get cmfdb","",x);
6705 if (x < 0) /* Error */
6706 goto xgetx; /* or reparse needed */
6707 if (cmresult.fcode != _CMKEY) /* Break out of loop if not a switch */
6708 break;
6709 c = cmgbrk(); /* Get break character */
6710 getval = (c == ':' || c == '='); /* to see how they ended the switch */
6711 if (getval && !(cmresult.kflags & CM_ARG)) {
6712 printf("?This switch does not take arguments\n");
6713 x = -9;
6714 goto xgetx;
6715 }
6716 n = cmresult.nresult; /* Numeric result = switch value */
6717 debug(F101,"ftp get switch","",n);
6718
6719 if (!getval && (cmgkwflgs() & CM_ARG)) {
6720 printf("?This switch requires an argument\n");
6721 x = -9;
6722 goto xgetx;
6723 }
6724 switch (n) { /* Process the switch */
6725 case SND_ASN: /* /AS-NAME: */
6726 debug(F101,"ftp get /as-name getval","",getval);
6727 if (!getval) break;
6728 if ((x = cmfld("Name to store it under","",&s,NULL)) < 0) {
6729 if (x == -3) {
6730 printf("?name required\n");
6731 x = -9;
6732 }
6733 goto xgetx;
6734 }
6735 s = brstrip(s);
6736 if (!*s) s = NULL;
6737 makestr(&(pv[n].sval),s);
6738 pv[n].ival = 1;
6739 break;
6740
6741 case SND_BIN: /* /BINARY */
6742 case SND_TXT: /* /TEXT or /ASCII */
6743 case SND_TEN: /* /TENEX */
6744 pv[SND_BIN].ival = 0;
6745 pv[SND_TXT].ival = 0;
6746 pv[SND_TEN].ival = 0;
6747 pv[n].ival = 1;
6748 break;
6749
6750 #ifdef PUTPIPE
6751 case SND_CMD: /* These take no args */
6752 if (nopush) {
6753 printf("?Sorry, system command access is disabled\n");
6754 x = -9;
6755 goto xgetx;
6756 }
6757 #ifdef PIPESEND
6758 else if (rcvfilter) {
6759 printf("?Sorry, no PUT /COMMAND when SEND FILTER selected\n");
6760 x = -9;
6761 goto xgetx;
6762 }
6763 #endif /* PIPESEND */
6764 sw.hlpmsg = "Command, or switch"; /* Change help message */
6765 pv[n].ival = 1; /* Just set the flag */
6766 pv[SND_ARR].ival = 0;
6767 break;
6768 #endif /* PUTPIPE */
6769
6770 case SND_SHH: /* /QUIET */
6771 case SND_RES: /* /RECOVER (reget) */
6772 case SND_NOB: /* /NOBACKUPFILES */
6773 case SND_DEL: /* /DELETE */
6774 case SND_UPD: /* /UPDATE */
6775 case SND_USN: /* /UNIQUE */
6776 case SND_NOD: /* /NODOTFILES */
6777 case SND_REC: /* /RECOVER */
6778 case SND_MAI: /* /TO-SCREEN */
6779 pv[n].ival = 1; /* Just set the flag */
6780 break;
6781
6782 case SND_DIF: /* /DATES-DIFFER */
6783 pv[SND_COL].ival = XYFX_M; /* Now it's a collision option */
6784 pv[n].ival = 1;
6785 break;
6786
6787 case SND_COL: /* /COLLISION: */
6788 if ((x = cmkey(ftpcolxtab,nftpcolx,"","",xxstring)) < 0)
6789 goto xgetx;
6790 if (x == XYFX_M)
6791 pv[SND_DIF].ival = 1; /* (phase this out) */
6792 pv[n].ival = x; /* this should be sufficient */
6793 break;
6794
6795 case SND_ERR: /* /ERROR-ACTION */
6796 if ((x = cmkey(qorp,2,"","",xxstring)) < 0)
6797 goto xgetx;
6798 pv[n].ival = x;
6799 break;
6800
6801 case SND_EXC: /* Exception list */
6802 if (!getval) break;
6803 if ((x = cmfld("Pattern","",&s,xxstring)) < 0) {
6804 if (x == -3) {
6805 printf("?Pattern required\n");
6806 x = -9;
6807 }
6808 goto xgetx;
6809 }
6810 if (s) if (!*s) s = NULL;
6811 makestr(&(pv[n].sval),s);
6812 if (pv[n].sval)
6813 pv[n].ival = 1;
6814 break;
6815
6816 #ifdef PIPESEND
6817 case SND_FLT:
6818 debug(F101,"ftp get /filter getval","",getval);
6819 if (!getval) break;
6820 if ((x = cmfld("Filter program to send through","",&s,NULL)) < 0) {
6821 if (x == -3)
6822 s = "";
6823 else
6824 goto xgetx;
6825 }
6826 s = brstrip(s);
6827 if (pv[SND_MAI].ival < 1) {
6828 y = strlen(s);
6829 /* Make sure they included "\v(...)" */
6830 for (x = 0; x < y; x++) {
6831 if (s[x] != '\\') continue;
6832 if (s[x+1] == 'v') break;
6833 }
6834 if (x == y) {
6835 printf(
6836 "?Filter must contain a replacement variable for filename.\n"
6837 );
6838 x = -9;
6839 goto xgetx;
6840 }
6841 }
6842 if (*s) {
6843 pv[n].ival = 1;
6844 makestr(&(pv[n].sval),s);
6845 } else {
6846 pv[n].ival = 0;
6847 makestr(&(pv[n].sval),NULL);
6848 }
6849 break;
6850 #endif /* PIPESEND */
6851
6852 case SND_NAM:
6853 if (!getval) break;
6854 if ((x = cmkey(fntab,nfntab,"","automatic",xxstring)) < 0)
6855 goto xgetx;
6856 debug(F101,"ftp get /filenames","",x);
6857 pv[n].ival = x;
6858 break;
6859
6860 case SND_SMA: /* Smaller / larger than */
6861 case SND_LAR: {
6862 CK_OFF_T y;
6863 if (!getval) break;
6864 if ((x = cmnumw("Size in bytes","0",10,&y,xxstring)) < 0)
6865 goto xgetx;
6866 pv[n].wval = y;
6867 break;
6868 }
6869 case SND_FIL: /* Name of file containing filnames */
6870 if (!getval) break;
6871 if ((x = cmifi("Name of file containing list of filenames",
6872 "",&s,&y,xxstring)) < 0) {
6873 if (x == -3) {
6874 printf("?Filename required\n");
6875 x = -9;
6876 }
6877 goto xgetx;
6878 } else if (y && iswild(s)) {
6879 printf("?Wildcards not allowed BBB\n");
6880 x = -9;
6881 goto xgetx;
6882 }
6883 if (s) if (!*s) s = NULL;
6884 makestr(&(pv[n].sval),s);
6885 if (pv[n].sval)
6886 pv[n].ival = 1;
6887 break;
6888
6889 case SND_MOV: /* MOVE after */
6890 case SND_REN: /* RENAME after */
6891 case SND_SRN: { /* SERVER-RENAME */
6892 char * m = "";
6893 switch (n) {
6894 case SND_MOV:
6895 m =
6896 "Device and/or directory for incoming file after reception";
6897 break;
6898 case SND_REN:
6899 m = "New name for incoming file after reception";
6900 break;
6901 case SND_SRN:
6902 m = "New name for source file on server after reception";
6903 break;
6904 }
6905 if (!getval) break;
6906 if ((x = cmfld(m, "", &s, n == SND_MOV ? xxstring : NULL)) < 0) {
6907 if (x == -3) {
6908 printf("%s\n", n == SND_MOV ?
6909 "?Destination required" :
6910 "?New name required"
6911 );
6912 x = -9;
6913 }
6914 goto xgetx;
6915 }
6916 makestr(&(pv[n].sval),*s ? brstrip(s) : NULL);
6917 pv[n].ival = (pv[n].sval) ? 1 : 0;
6918 break;
6919 }
6920 #ifndef NOCSETS
6921 case SND_CSL: /* Local character set */
6922 case SND_CSR: /* Remote (server) charset */
6923 if ((x = cmkey(fcstab,nfilc,"","",xxstring)) < 0)
6924 return((x == -3) ? -2 : x);
6925 if (n == SND_CSL)
6926 x_csl = x;
6927 else
6928 x_csr = x;
6929 x_xla = 1; /* Overrides global OFF setting */
6930 break;
6931
6932 case SND_XPA: /* Transparent */
6933 x_xla = 0;
6934 x_csr = -1;
6935 x_csl = -1;
6936 break;
6937 #endif /* NOCSETS */
6938
6939 case SND_NML:
6940 if ((x = cmofi("Local filename","-",&s,xxstring)) < 0)
6941 goto xgetx;
6942 makestr(&ftp_nml,s);
6943 break;
6944
6945 case SND_PAT: /* /PATTERN: */
6946 if (!getval) break;
6947 if ((x = cmfld("Pattern","*", &s, xxstring)) < 0)
6948 goto xgetx;
6949 makestr(&(pv[n].sval),*s ? brstrip(s) : NULL);
6950 pv[n].ival = (pv[n].sval) ? 1 : 0;
6951 break;
6952
6953 case SND_NLS: /* /NLST */
6954 pv[n].ival = 1; /* Use NLST */
6955 pv[SND_MLS].ival = 0; /* Don't use MLSD */
6956 break;
6957
6958 case SND_MLS: /* /MLSD */
6959 pv[n].ival = 1; /* Use MLSD */
6960 pv[SND_NLS].ival = 0; /* Don't use NLST */
6961 break;
6962
6963 default: /* /AFTER, /PERMISSIONS, etc... */
6964 printf("?Sorry, \"%s\" works only with [M]PUT\n",atmbuf);
6965 x = -9;
6966 goto xgetx;
6967 }
6968 }
6969 line[0] = NUL;
6970 cmarg = line;
6971 cmarg2 = asnambuf;
6972 s = line;
6973 /*
6974 For GET, we want to parse an optional as-name, like with PUT.
6975 For MGET, we must parse a list of names, and then send NLST or MLSD
6976 commands for each name separately.
6977 */
6978 switch (cmresult.fcode) { /* How did we get out of switch loop */
6979 case _CMFLD: /* Field */
6980 if (!getone) {
6981 s = brstrip(cmresult.sresult);
6982 makestr(&(mgetlist[mgetn++]),s);
6983 while ((x = cmfld("Remote filename","",&s,xxstring)) != -3) {
6984 if (x < 0)
6985 goto xgetx;
6986 makestr(&(mgetlist[mgetn++]),brstrip(s));
6987 if (mgetn >= MGETMAX) {
6988 printf("?Too many items in MGET list\n");
6989 goto xgetx;
6990 }
6991 }
6992 if ((x = cmcfm()) < 0)
6993 goto xgetx;
6994 } else {
6995 s = brstrip(cmresult.sresult);
6996 ckstrncpy(line,s,LINBUFSIZ);
6997 if ((x = cmfld("Name to store it under","",&s,xxstring)) < 0)
6998 if (x != -3)
6999 goto xgetx;
7000 s = brstrip(s);
7001 ckstrncpy(asnambuf,s,CKMAXPATH+1);
7002 if ((x = cmcfm()) < 0)
7003 goto xgetx;
7004 }
7005 break;
7006 case _CMCFM: /* Confirmation */
7007 break;
7008 default:
7009 printf("?Unexpected function code: %d\n",cmresult.fcode);
7010 x = -9;
7011 goto xgetx;
7012 }
7013 if (pv[SND_REC].ival > 0) /* /RECURSIVE */
7014 recursive = 2;
7015
7016 if (pv[SND_BIN].ival > 0) { /* /BINARY really means binary... */
7017 forcetype = 1; /* So skip the name-pattern match */
7018 ftp_typ = XYFT_B; /* Set binary */
7019 } else if (pv[SND_TXT].ival > 0) { /* Similarly for /TEXT... */
7020 forcetype = 1;
7021 ftp_typ = XYFT_T;
7022 } else if (pv[SND_TEN].ival > 0) { /* and /TENEX*/
7023 forcetype = 1;
7024 ftp_typ = FTT_TEN;
7025 } else if (ftp_cmdlin && ftp_xfermode == XMODE_M) {
7026 forcetype = 1;
7027 ftp_typ = binary;
7028 g_ftp_typ = binary;
7029 }
7030 if (pv[SND_ASN].ival > 0 && pv[SND_ASN].sval && !asnambuf[0]) {
7031 char * p;
7032 p = brstrip(pv[SND_ASN].sval); /* As-name */
7033 ckstrncpy(asnambuf,p,CKMAXPATH+1);
7034 }
7035 debug(F110,"ftp get asnambuf",asnambuf,0);
7036
7037 #ifdef PIPESEND
7038 if (pv[SND_CMD].ival > 0) { /* /COMMAND - strip any braces */
7039 char * p;
7040 p = asnambuf;
7041 debug(F110,"GET /COMMAND before stripping",p,0);
7042 p = brstrip(p);
7043 debug(F110,"GET /COMMAND after stripping",p,0);
7044 if (!*p) {
7045 printf("?Sorry, a command to write to is required\n");
7046 x = -9;
7047 goto xgetx;
7048 }
7049 pipename = p;
7050 pipesend = 1;
7051 }
7052 #endif /* PIPESEND */
7053
7054 /* Set up /MOVE and /RENAME */
7055
7056 #ifdef COMMENT
7057 /* Conflict exists only for PUT - removed 13 Mar 2006 - fdc */
7058 if (pv[SND_DEL].ival > 0 &&
7059 (pv[SND_MOV].ival > 0 || pv[SND_REN].ival > 0)) {
7060 printf("?Sorry, /DELETE conflicts with /MOVE or /RENAME\n");
7061 x = -9;
7062 goto xgetx;
7063 }
7064 #endif /* COMMENT */
7065 #ifdef CK_TMPDIR
7066 if (pv[SND_MOV].ival > 0 && pv[SND_MOV].sval) {
7067 int len;
7068 char * p = pv[SND_MOV].sval;
7069 len = strlen(p);
7070 if (!isdir(p)) { /* Check directory */
7071 #ifdef CK_MKDIR
7072 char * s = NULL;
7073 s = (char *)malloc(len + 4);
7074 if (s) {
7075 strcpy(s,p); /* safe */
7076 #ifdef datageneral
7077 if (s[len-1] != ':') { s[len++] = ':'; s[len] = NUL; }
7078 #else
7079 if (s[len-1] != '/') { s[len++] = '/'; s[len] = NUL; }
7080 #endif /* datageneral */
7081 s[len++] = 'X';
7082 s[len] = NUL;
7083 #ifdef NOMKDIR
7084 x = -1;
7085 #else
7086 x = zmkdir(s);
7087 #endif /* NOMKDIR */
7088 free(s);
7089 if (x < 0) {
7090 printf("?Can't create \"%s\"\n",p);
7091 x = -9;
7092 goto xgetx;
7093 }
7094 }
7095 #else
7096 printf("?Directory \"%s\" not found\n",p);
7097 x = -9;
7098 goto xgetx;
7099 #endif /* CK_MKDIR */
7100 }
7101 makestr(&rcv_move,p);
7102 moving = 1;
7103 }
7104 #endif /* CK_TMPDIR */
7105
7106 if (pv[SND_REN].ival > 0) { /* /RENAME */
7107 char * p = pv[SND_REN].sval;
7108 if (!p) p = "";
7109 if (!*p) {
7110 printf("?New name required for /RENAME\n");
7111 x = -9;
7112 goto xgetx;
7113 }
7114 p = brstrip(p);
7115 #ifndef NOSPL
7116 /* If name given is wild, rename string must contain variables */
7117 if (mget && !getone) {
7118 char * s = tmpbuf;
7119 x = TMPBUFSIZ;
7120 zzstring(p,&s,&x);
7121 if (!strcmp(tmpbuf,p)) {
7122 printf(
7123 "?/RENAME for file group must contain variables such as \\v(filename)\n"
7124 );
7125 x = -9;
7126 goto xgetx;
7127 }
7128 }
7129 #endif /* NOSPL */
7130 renaming = 1;
7131 makestr(&rcv_rename,p);
7132 debug(F110,"FTP rcv_rename",rcv_rename,0);
7133 }
7134 if (!cmarg[0] && mgetn == 0 && getone && pv[SND_FIL].ival < 1) {
7135 printf("?Filename required but not given\n");
7136 x = -9;
7137 goto xgetx;
7138 } else if ((cmarg[0] || mgetn > 0) && pv[SND_FIL].ival > 0) {
7139 printf("?You can't give both /LISTFILE and a remote filename\n");
7140 x = -9;
7141 goto xgetx;
7142 }
7143 CHECKCONN(); /* Check connection */
7144
7145 if (pv[SND_COL].ival > -1)
7146 x_fnc = pv[SND_COL].ival;
7147
7148 #ifndef NOSPL
7149 /* If as-name given for MGET, as-name must contain variables */
7150 if (mget && !getone && asnambuf[0] && x_fnc != XYFX_A) {
7151 char * s = tmpbuf;
7152 x = TMPBUFSIZ;
7153 zzstring(asnambuf,&s,&x);
7154 if (!strcmp(tmpbuf,asnambuf)) {
7155 printf(
7156 "?As-name for MGET must contain variables such as \\v(filename)\n"
7157 );
7158 x = -9;
7159 goto xgetx;
7160 }
7161 }
7162 #endif /* NOSPL */
7163
7164 /* doget: */
7165
7166 if (pv[SND_SHH].ival > 0 || ftp_nml) { /* GET /QUIET... */
7167 fdispla = 0;
7168 } else {
7169 displa = 1;
7170 if (mdel || ftp_deb)
7171 fdispla = XYFD_B;
7172 }
7173 deleting = 0;
7174 if (pv[SND_DEL].ival > 0) /* /DELETE was specified */
7175 deleting = 1;
7176 if (pv[SND_EXC].ival > 0)
7177 makelist(pv[SND_EXC].sval,rcvexcept,NSNDEXCEPT);
7178 if (pv[SND_SMA].wval > -1)
7179 getsmaller = pv[SND_SMA].wval;
7180 if (pv[SND_LAR].wval > -1)
7181 getlarger = pv[SND_LAR].wval;
7182 if (pv[SND_NAM].ival > -1)
7183 x_cnv = pv[SND_NAM].ival;
7184 if (pv[SND_ERR].ival > -1)
7185 geterror = pv[SND_ERR].ival;
7186 if (pv[SND_MAI].ival > -1)
7187 toscreen = 1;
7188
7189 if (pv[SND_NLS].ival > 0) { /* Force NLST or MLSD? */
7190 mgetmethod = SND_NLS;
7191 mgetforced = 1;
7192 } else if (pv[SND_MLS].ival > 0) {
7193 mgetmethod = SND_MLS;
7194 mgetforced = 1;
7195 }
7196
7197 #ifdef FTP_RESTART
7198 if (pv[SND_RES].ival > 0) {
7199 if (!ftp_typ) {
7200 printf("?Sorry, GET /RECOVER requires binary mode\n");
7201 x = -9;
7202 goto xgetx;
7203 #ifdef COMMENT
7204 /* Not true - the fact that the initial REST fails does not mean */
7205 /* it will fail here. */
7206 } else if (!okrestart) {
7207 printf("WARNING: Server might not support restart...\n");
7208 #endif /* COMMENT */
7209 }
7210 restart = 1;
7211 }
7212 #endif /* FTP_RESTART */
7213
7214 #ifdef PIPESEND
7215 if (pv[SND_FLT].ival > 0) { /* Have SEND FILTER? */
7216 if (pipesend) {
7217 printf("?Switch conflict: /FILTER and /COMMAND\n");
7218 x = -9;
7219 goto xgetx;
7220 }
7221 makestr(&rcvfilter,pv[SND_FLT].sval);
7222 debug(F110,"ftp get /FILTER", rcvfilter, 0);
7223 }
7224 if (rcvfilter || pipesend) { /* /RESTART */
7225 #ifdef FTP_RESTART
7226 if (restart) { /* with pipes or filters */
7227 printf("?Switch conflict: /FILTER or /COMMAND and /RECOVER\n");
7228 x = -9;
7229 goto xgetx;
7230 }
7231 #endif /* FTP_RESTART */
7232 if (pv[SND_UPD].ival > 0 || x_fnc == XYFX_M || x_fnc == XYFX_U) {
7233 printf(
7234 "?Switch conflict: /FILTER or /COMMAND and Date Checking\n");
7235 x = -9;
7236 goto xgetx;
7237 }
7238 }
7239 #endif /* PIPESEND */
7240
7241 tfc = (CK_OFF_T)0; /* Initialize stats and counters */
7242 filcnt = 0;
7243 pktnum = 0;
7244 rpackets = 0L;
7245
7246 if (pv[SND_FIL].ival > 0) {
7247 if (zopeni(ZMFILE,pv[SND_FIL].sval) < 1) {
7248 debug(F111,"ftp get can't open listfile",pv[SND_FIL].sval,errno);
7249 printf("?Failure to open listfile - \"%s\"\n",pv[SND_FIL].sval);
7250 x = -9;
7251 goto xgetx;
7252 }
7253 if (zsinl(ZMFILE,tmpbuf,CKMAXPATH) < 0) { /* Read a line */
7254 zclose(ZMFILE); /* Failed */
7255 debug(F110,"ftp get listfile EOF",pv[SND_FIL].sval,0);
7256 printf("?Empty listfile - \"%s\"\n",pv[SND_FIL].sval);
7257 x = -9;
7258 goto xgetx;
7259 }
7260 listfile = 1;
7261 debug(F110,"ftp get listfile first",tmpbuf,0);
7262 makestr(&(mgetlist[0]),tmpbuf);
7263 }
7264 t0 = gmstimer(); /* Record starting time */
7265
7266 updating = 0; /* Checking dates? */
7267 if (pv[SND_UPD].ival > 0 || (!mdel && x_fnc == XYFX_U))
7268 updating = 1;
7269 if (pv[SND_DIF].ival > 0 || x_fnc == XYFX_M)
7270 updating = 2;
7271 if (updating) /* These switches force FTP DATES ON */
7272 ftp_dates |= 2;
7273
7274 what = mdel ? W_FTP|W_FT_DELE : W_RECV|W_FTP; /* What we're doing */
7275
7276 cancelgroup = 0; /* Group not canceled yet */
7277 if (!(ftp_xfermode == XMODE_A && patterns && get_auto && !forcetype))
7278 changetype(ftp_typ,0); /* Change to requested type */
7279 binary = ftp_typ; /* For file-transfer display */
7280 first = 1; /* For MGET list */
7281 done = 0; /* Loop control */
7282
7283 #ifdef CK_TMPDIR
7284 if (dldir && !f_tmpdir) { /* If they have a download directory */
7285 if ((s = zgtdir())) { /* Get current directory */
7286 if (zchdir(dldir)) { /* Change to download directory */
7287 ckstrncpy(savdir,s,TMPDIRLEN);
7288 f_tmpdir = 1; /* Remember that we did this */
7289 }
7290 }
7291 }
7292 #endif /* CK_TMPDIR */
7293
7294 if (ftp_nml) { /* /NAMELIST */
7295 debug(F110,"ftp GET ftp_nml",ftp_nml,0);
7296 if (ftp_nml[0] == '-' && ftp_nml[1] == 0)
7297 fp_nml = stdout;
7298 else
7299 fp_nml = fopen(ftp_nml, "wb");
7300 if (!fp_nml) {
7301 printf("?%s: %s\n",ftp_nml,ck_errstr());
7302 goto xgetx;
7303 }
7304 }
7305 while (!done && !cancelgroup) { /* Loop for all files */
7306 /* or until canceled. */
7307 #ifdef FTP_PROXY
7308 /* do something here if proxy */
7309 #endif /* FTP_PROXY */
7310
7311 rs_len = (CK_OFF_T)0; /* REGET position */
7312 cancelfile = 0; /* This file not canceled yet */
7313 haspath = 0; /* Recalculate this each time thru */
7314
7315 if (getone) { /* GET */
7316 char * p;
7317 s = line;
7318 src = line; /* Server name */
7319 done = 1;
7320 debug(F111,"ftp get file",s,0);
7321 } else if (mget) { /* MGET */
7322 src = mgetlist[mgetx];
7323 debug(F111,"ftp mget remote_files A",src,first);
7324 s = (char *)remote_files(first,
7325 (CHAR *)mgetlist[mgetx],
7326 (CHAR *)pv[SND_PAT].sval,
7327 0
7328 );
7329 debug(F110,"ftp mget remote_files B",s,0);
7330 if (!s) s = "";
7331 if (!*s) {
7332 first = 1;
7333 if (listfile) { /* Names from listfile */
7334 again:
7335 tmpbuf[0] = NUL;
7336 while (!tmpbuf[0]) {
7337 if (zsinl(ZMFILE,tmpbuf,CKMAXPATH) < 0) {
7338 zclose(ZMFILE);
7339 debug(F110,"ftp get listfile EOF",
7340 pv[SND_FIL].sval,0);
7341 makestr(&(mgetlist[0]),NULL);
7342 s = NULL;
7343 done = 1;
7344 break;
7345 }
7346 }
7347 if (done)
7348 continue;
7349
7350 makestr(&(mgetlist[0]),tmpbuf);
7351 debug(F110,"ftp get listfile next",tmpbuf,0);
7352 s = (char *)remote_files(first,
7353 (CHAR *)mgetlist[0],
7354 (CHAR *)pv[SND_PAT].sval,
7355 0
7356 );
7357 debug(F110,"ftp mget remote_files C",s,0);
7358 if (!s) {
7359 ftscreen(SCR_FN,'F',(CK_OFF_T)0,s);
7360 ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,"File not found");
7361 tlog(F110,"ftp get file not found:",s,0);
7362 goto again;
7363 }
7364 } else { /* Names from command line */
7365 mgetx++;
7366 if (mgetx < mgetn)
7367 s = (char *)remote_files(first,
7368 (CHAR *)mgetlist[mgetx],
7369 (CHAR *)pv[SND_PAT].sval,
7370 0
7371 );
7372 else
7373 s = NULL;
7374 if (!s) mgetx++;
7375 debug(F111,"ftp mget remote_files D",s,mgetx);
7376 }
7377 if (!s) {
7378 if (!first || mgetx >= mgetn) {
7379 done = 1;
7380 break;
7381 } else if (geterror) {
7382 status = 0;
7383 done = 1;
7384 break;
7385 } else {
7386 continue;
7387 }
7388 }
7389 }
7390 }
7391 debug(F111,"ftp mget remote_files E",s,0);
7392 /*
7393 The semantics of NLST are ill-defined. Suppose we have just sent
7394 NLST /path/[a-z]*. Most servers send back names like /path/foo,
7395 /path/bar, etc. But some send back only foo and bar, and subsequent
7396 RETR commands based on the pathless names are not going to work.
7397 */
7398 if (servertype == SYS_UNIX && !ckstrchr(s,'/')) {
7399 char * s3;
7400 if ((s3 = ckstrrchr(mgetlist[mgetx],'/'))) {
7401 int len, left = 4096;
7402 char * tmp = xtmpbuf;
7403 len = s3 - mgetlist[mgetx] + 1;
7404 ckstrncpy(tmp,mgetlist[mgetx],left);
7405 tmp += len;
7406 left -= len;
7407 ckstrncpy(tmp,s,left);
7408 s = xtmpbuf;
7409 debug(F111,"ftp mget remote_files F",s,0);
7410 }
7411 }
7412 first = 0;
7413 skipthis = 0; /* File selection... */
7414 msg = "";
7415 nam = s; /* Filename (without path) */
7416 rc = 0; /* Initial return code */
7417 s2 = "";
7418
7419 if (!getone && !skipthis) { /* For MGET and MDELETE... */
7420 char c, * p = s;
7421 int srvpath = 0;
7422 int usrpath = 0;
7423 int i, k = 0;
7424
7425 debug(F111,"ftp mget havetype",s,havetype);
7426 if (havetype > 0 && havetype != FTYP_FILE) {
7427 /* Server says it's not file... */
7428 debug(F110,"ftp mget not-a-file",s,0);
7429 continue;
7430 }
7431 /*
7432 Explanation: Some ftp servers (such as wu-ftpd) return a recursive list.
7433 But if the client did not ask for a recursive list, we have to ignore any
7434 server files that include a pathname that extends beyond any path that
7435 was included in the user's request.
7436
7437 User's filespec is blah or path/blah (or other non-UNIX syntax). We need to
7438 get the user's path segment. Then, for each incoming file, if it begins
7439 with the same path segment, we must strip it (point past it).
7440 */
7441 src = mgetlist[mgetx]; /* In case it moved! */
7442 if (src) {
7443 for (i = 0; src[i]; i++) { /* Find rightmost path separator */
7444 if (ispathsep(src[i])) /* in user's pathname */
7445 k = i + 1;
7446 }
7447 } else {
7448 src = "";
7449 }
7450 usrpath = k; /* User path segment length */
7451 debug(F111,"ftp get usrpath",src,usrpath);
7452
7453 p = s; /* Server filename */
7454 while ((c = *p++)) { /* Look for path in server filename */
7455 if (ispathsep(c)) {
7456 /* haspath++; */
7457 nam = p; /* Pathless name (for ckmatch) */
7458 srvpath = p - s; /* Server path segment length */
7459 }
7460 }
7461 debug(F111,"ftp get srvpath",s,srvpath);
7462
7463 if (usrpath == 0) {
7464 /*
7465 Here we handle the case where the user said "mget foo" where foo is a
7466 directory name, and the server is sending back names like "foo/file1",
7467 "foo/file2", etc. This is a nasty trick but it's necessary because the
7468 user can't compensate by typing "mget foo/" because then the server is
7469 likely to send back "foo//file1, foo//file2" etc, and we still won't
7470 get a match...
7471 */
7472 int srclen = 0, srvlen = 0;
7473 if (src) srclen = strlen(src);
7474 if (s) srvlen = strlen(s);
7475 if (src && (srvlen > srclen)) {
7476 if (!strncmp(src,s,srclen) && ispathsep(s[srclen])) {
7477 char * tmpsrc = NULL;
7478 tmpsrc = (char *)malloc(srclen + 2);
7479 strncpy(tmpsrc,src,srclen);
7480 tmpsrc[srclen] = s[srclen];
7481 tmpsrc[srclen+1] = NUL;
7482 free(mgetlist[mgetx]);
7483 mgetlist[mgetx] = tmpsrc;
7484 tmpsrc = NULL;
7485 src = mgetlist[mgetx];
7486 usrpath = srclen+1;
7487 }
7488 }
7489 }
7490 /*
7491 If as-name not given and server filename includes path that matches
7492 the pathname from the user's file specification, we must trim the common
7493 path prefix from the server's name when constructing the local name.
7494 */
7495 if (src && /* Wed Sep 25 17:27:48 2002 */
7496 !asnambuf[0] &&
7497 !recursive && /* Thu Sep 19 16:11:59 2002 */
7498 (srvpath > 0) &&
7499 !strncmp(src,s,usrpath)) {
7500 s2 = s + usrpath; /* Local name skips past remote path */
7501 }
7502 #ifdef COMMENT
7503 /* This doesn't work if the path prefix contains wildcards! */
7504 haspath = (srvpath > usrpath);
7505 #else
7506 { /* Count path segments instead */
7507 int x1 = 0, x2 = 0;
7508 char *p;
7509 for (p = s; *p; p++)
7510 if (ispathsep(*p)) x1++;
7511 for (p = src; *p; p++) {
7512 if (ispathsep(*p)) x2++;
7513 }
7514 haspath = recursive ? x1 || x2 : x1 > x2;
7515 debug(F111,"ftp get server path segments",s,x1);
7516 debug(F111,"ftp get user path segments",src,x2);
7517 }
7518
7519 #endif /* COMMENT */
7520 debug(F111,"ftp get haspath",s+usrpath,haspath);
7521
7522 if (haspath) { /* Server file has path segments? */
7523 if (!recursive) { /* [M]GET /RECURSIVE? */
7524 /*
7525 We did not ask for a recursive listing, but the server is sending us one
7526 anyway (as wu-ftpd is wont to do). We get here if the current filename
7527 includes a path segment beyond any path segment we asked for in our
7528 non-recursive [M]GET command. We MUST skip this file.
7529 */
7530 debug(F111,"ftp get skipping because of path",s,0);
7531 continue;
7532 }
7533 }
7534 } else if (getone && !skipthis) { /* GET (not MGET) */
7535 char * p = nam;
7536 while ((c = *p++)) { /* Handle path in local name */
7537 if (ispathsep(c)) {
7538 if (recursive) { /* If recursive, keep it */
7539 haspath = 1;
7540 break;
7541 } else { /* Otherwise lose it. */
7542 nam = p;
7543 }
7544 }
7545 }
7546 s2 = nam;
7547 }
7548 if (!*nam) /* Name without path */
7549 nam = s;
7550
7551 if (!skipthis && pv[SND_NOD].ival > 0) { /* /NODOTFILES */
7552 if (nam[0] == '.')
7553 continue;
7554 }
7555 if (!skipthis && rcvexcept[0]) { /* /EXCEPT: list */
7556 int xx;
7557 for (i = 0; i < NSNDEXCEPT; i++) {
7558 if (!rcvexcept[i]) {
7559 break;
7560 }
7561 xx = ckmatch(rcvexcept[i], nam, servertype == SYS_UNIX, 1);
7562 debug(F111,"ftp mget /except match",rcvexcept[i],xx);
7563 if (xx) {
7564 tlog(F100," refused: exception list","",0);
7565 msg = "Refused: Exception List";
7566 skipthis++;
7567 break;
7568 }
7569 }
7570 }
7571 if (!skipthis && pv[SND_NOB].ival > 0) { /* /NOBACKUPFILES */
7572 if (ckmatch(
7573 #ifdef CKREGEX
7574 "*.~[0-9]*~"
7575 #else
7576 "*.~*~"
7577 #endif /* CKREGEX */
7578 ,nam,0,1) > 0)
7579 continue;
7580 }
7581 if (!x_xla) { /* If translation is off */
7582 x_csl = -2; /* unset the charsets */
7583 x_csr = -2;
7584 }
7585 ckstrncpy(filnam,s,CKMAXPATH); /* For \v(filename) */
7586 if (!*s2) /* Local name */
7587 s2 = asnambuf; /* As-name */
7588
7589 if (!*s2) /* Sat Nov 16 19:19:39 2002 */
7590 s2 = recursive ? s : nam; /* Fri Jan 10 13:15:19 2003 */
7591
7592 debug(F110,"ftp get filnam ",s,0);
7593 debug(F110,"ftp get asname A",s2,0);
7594
7595 /* Receiving to real file */
7596 if (!pipesend &&
7597 #ifdef PIPESEND
7598 !rcvfilter &&
7599 #endif /* PIPESEND */
7600 !toscreen) {
7601 #ifndef NOSPL
7602 /* Do this here so we can decide whether to skip */
7603 if (cmd_quoting && !skipthis && asnambuf[0]) {
7604 int n; char *p;
7605 n = TMPBUFSIZ;
7606 p = tmpbuf;
7607 zzstring(asnambuf,&p,&n);
7608 s2 = tmpbuf;
7609 debug(F111,"ftp get asname B",s2,updating);
7610 }
7611 #endif /* NOSPL */
7612
7613 local = *s2 ? s2 : s;
7614
7615 if (!skipthis && x_fnc == XYFX_D) { /* File Collision = Discard */
7616 CK_OFF_T x;
7617 x = zchki(local);
7618 debug(F111,"ftp get DISCARD zchki",local,x);
7619 if (x > -1) {
7620 skipthis++;
7621 debug(F110,"ftp get skip name",local,0);
7622 tlog(F100," refused: name","",0);
7623 msg = "Refused: Name";
7624 }
7625 }
7626
7627 #ifdef DOUPDATE
7628 if (!skipthis && updating) { /* If updating and not yet skipping */
7629 if (zchki(local) > -1) {
7630 x = chkmodtime(local,s,0);
7631 #ifdef DEBUG
7632 if (deblog) {
7633 if (updating == 2)
7634 debug(F111,"ftp get /dates-diff chkmodtime",local,x);
7635 else
7636 debug(F111,"ftp get /update chkmodtime",local,x);
7637 }
7638 #endif /* DEBUG */
7639 if ((updating == 1 && x > 0) || /* /UPDATE */
7640 (updating == 2 && x == 1)) { /* /DATES-DIFFER */
7641 skipthis++;
7642 tlog(F100," refused: date","",0);
7643 msg = "Refused: Date";
7644 debug(F110,"ftp get skip date",local,0);
7645 }
7646 }
7647 }
7648 #endif /* DOUPDATE */
7649 }
7650 /* Initialize file size to -1 in case server doesn't understand */
7651 /* SIZE command, so xxscreen() will know we don't know the size */
7652
7653 fsize = (CK_OFF_T)-1;
7654
7655 /* Ask for size now only if we need it for selection */
7656 /* because if you're going thru a list 100,000 files to select */
7657 /* a small subset, 100,000 SIZE commands can take hours... */
7658
7659 gotsize = 0;
7660 if (!mdel && !skipthis && /* Don't need size for DELE... */
7661 (getsmaller >= (CK_OFF_T)0 || getlarger >= (CK_OFF_T)0)) {
7662 if (havesize >= (CK_OFF_T)0) { /* Already have file size? */
7663 fsize = havesize;
7664 gotsize = 1;
7665 } else { /* No - must ask server */
7666 /*
7667 Prior to sending the NLST command we necessarily put the
7668 server into ASCII mode. We must now put it back into the
7669 the requested mode so the upcoming SIZE command returns
7670 right kind of size; this is especially important for
7671 GET /RECOVER; otherwise the server returns the "ASCII" size
7672 of the file, rather than its true size.
7673 */
7674 changetype(ftp_typ,0); /* Change to requested type */
7675 fsize = (CK_OFF_T)-1;
7676 if (sizeok) {
7677 x = ftpcmd("SIZE",s,x_csl,x_csr,ftp_vbm);
7678 if (x == REPLY_COMPLETE) {
7679 fsize = ckatofs(&ftp_reply_str[4]);
7680 gotsize = 1;
7681 }
7682 }
7683 }
7684 if (gotsize) {
7685 if (getsmaller >= (CK_OFF_T)0 && fsize >= getsmaller)
7686 skipthis++;
7687 if (getlarger >= (CK_OFF_T)0 && fsize <= getlarger)
7688 skipthis++;
7689 if (skipthis) {
7690 debug(F111,"ftp get skip size",s,fsize);
7691 tlog(F100," refused: size","",0);
7692 msg = "Refused: Size";
7693 }
7694 #ifdef COMMENT
7695 } else if (getone) {
7696 /* SIZE can fail for many reasons. Does the file exist? */
7697 x = ftpcmd("NLST",s,x_csl,x_csr,ftp_vbm);
7698 if (x != REPLY_COMPLETE) {
7699 printf(">>> FILE NOT FOUND: %s\n",s);
7700 break;
7701 }
7702 #endif /* COMMENT */
7703 }
7704 }
7705 if (skipthis) { /* Skipping this file? */
7706 ftscreen(SCR_FN,'F',(CK_OFF_T)0,s);
7707 if (msg)
7708 ftscreen(SCR_ST,ST_ERR,(CK_OFF_T)0,msg);
7709 else
7710 ftscreen(SCR_ST,ST_SKIP,(CK_OFF_T)0,s);
7711 continue;
7712 }
7713 if (fp_nml) { /* /NAMELIST only - no transfer */
7714 fprintf(fp_nml,"%s\n",s);
7715 continue;
7716 }
7717 if (recursive && haspath && !pipesend
7718 #ifdef PIPESEND
7719 && !rcvfilter
7720 #endif /* PIPESEND */
7721 ) {
7722 int x;
7723
7724 #ifdef NOMKDIR
7725 x = -1;
7726 #else
7727 x = zmkdir(s); /* Try to make the directory */
7728 #endif /* NOMKDIR */
7729
7730 if (x < 0) {
7731 rc = -1; /* Failure is fatal */
7732 if (geterror) {
7733 status = 0;
7734 ftscreen(SCR_EM,0,(CK_OFF_T)0,
7735 "Directory creation failure");
7736 break;
7737 }
7738 }
7739 }
7740
7741 /* Not skipping */
7742
7743 selected++; /* Count this file as selected */
7744 pn = NULL;
7745
7746 if (!gotsize && !mdel) { /* Didn't get size yet */
7747 if (havesize > (CK_OFF_T)-1) { /* Already have file size? */
7748 fsize = havesize;
7749 gotsize = 1;
7750 } else { /* No - must ask server */
7751 fsize = (CK_OFF_T)-1;
7752 if (sizeok) {
7753 x = ftpcmd("SIZE",s,x_csl,x_csr,ftp_vbm);
7754 if (x == REPLY_COMPLETE) {
7755 fsize = ckatofs(&ftp_reply_str[4]);
7756 gotsize = 1;
7757 }
7758 }
7759 }
7760 }
7761 if (mdel) { /* [M]DELETE */
7762 if (displa && !ftp_vbm)
7763 printf(" %s...",s);
7764 rc =
7765 (ftpcmd("DELE",s,x_csl,x_csr,ftp_vbm) == REPLY_COMPLETE) ? 1 : -1;
7766 if (rc > -1) {
7767 tlog(F110,"ftp mdelete",s,0);
7768 if (displa && !ftp_vbm)
7769 printf("OK\n");
7770 } else {
7771 tlog(F110,"ftp mdelete failed:",s,0);
7772 if (displa)
7773 printf("Failed\n");
7774 }
7775 #ifndef NOSPL
7776 #ifdef PIPESEND
7777 } else if (rcvfilter) { /* [M]GET with filter */
7778 int n; char * p;
7779 n = CKMAXPATH;
7780 p = tmpbuf; /* Safe - no asname with filter */
7781 zzstring(rcvfilter,&p,&n);
7782 if (n > -1)
7783 pn = tmpbuf;
7784 debug(F111,"ftp get rcvfilter",pn,n);
7785 #endif /* PIPESEND */
7786 #endif /* NOSPL */
7787 if (toscreen) s2 = "-";
7788 } else if (pipesend) { /* [M]GET /COMMAND */
7789 int n; char * p;
7790 n = CKMAXPATH;
7791 p = tmpbuf; /* Safe - no asname with filter */
7792 zzstring(pipename,&p,&n);
7793 if (n > -1)
7794 pn = tmpbuf;
7795 debug(F111,"ftp get pipename",pipename,n);
7796 if (toscreen) s2 = "-";
7797 } else { /* [M]GET with no pipes or filters */
7798 debug(F111,"ftp get s2 A",s2,x_cnv);
7799 if (toscreen) {
7800 s2 = "-"; /* (hokey convention for stdout) */
7801 } else if (!*s2) { /* No asname? */
7802 if (x_cnv) { /* If converting */
7803 nzrtol(s,tmpbuf,x_cnv,1,CKMAXPATH); /* convert */
7804 s2 = tmpbuf;
7805 debug(F110,"ftp get nzrtol",s2,0);
7806 } else /* otherwise */
7807 s2 = s; /* use incoming file's name */
7808 }
7809 debug(F110,"ftp get s2 B",s2,0);
7810
7811 /* If local file already exists, take collision action */
7812
7813 if (!pipesend &&
7814 #ifdef PIPESEND
7815 !rcvfilter &&
7816 #endif /* PIPESEND */
7817 !toscreen) {
7818 CK_OFF_T x;
7819 x = zchki(s2);
7820 debug(F111,"ftp get zchki",s2,x);
7821 debug(F111,"ftp get x_fnc",s2,x_fnc);
7822
7823 if (x > (CK_OFF_T)-1 && !restart) {
7824 int x = -1;
7825 char * newname = NULL;
7826
7827 switch (x_fnc) {
7828 case XYFX_A: /* Append */
7829 append = 1;
7830 break;
7831 case XYFX_R: /* Rename */
7832 case XYFX_B: /* Backup */
7833 znewn(s2,&newname); /* Make unique name */
7834 debug(F110,"ftp get znewn",newname,0);
7835 if (x_fnc == XYFX_B) { /* Backup existing file */
7836 x = zrename(s2,newname);
7837 debug(F111,"ftp get backup zrename",newname,x);
7838 } else { /* Rename incoming file */
7839 x = ckstrncpy(tmpbuf,newname,CKMAXPATH+1);
7840 s2 = tmpbuf;
7841 debug(F111,"ftp get rename incoming",newname,x);
7842 }
7843 if (x < 0) {
7844 ftscreen(SCR_EM,0,(CK_OFF_T)0,
7845 "Backup/Rename failed");
7846 x = 0;
7847 goto xgetx;
7848 }
7849 break;
7850 case XYFX_D: /* Discard (already handled above) */
7851 case XYFX_U: /* Update (ditto) */
7852 case XYFX_M: /* Update (ditto) */
7853 case XYFX_X: /* Overwrite */
7854 break;
7855 }
7856 }
7857 }
7858 }
7859 if (!mdel) {
7860 #ifdef PIPESEND
7861 debug(F111,"ftp get pn",pn,rcvfilter ? 1 : 0);
7862 #endif /* PIPESEND */
7863 if (pipesend && !toscreen)
7864 s2 = NULL;
7865 #ifdef DEBUG
7866 if (deblog) {
7867 debug(F101,"ftp get x_xla","",x_xla);
7868 debug(F101,"ftp get x_csl","",x_csl);
7869 debug(F101,"ftp get x_csr","",x_csr);
7870 debug(F101,"ftp get append","",append);
7871 }
7872 #endif /* DEBUG */
7873
7874 rc = getfile(s,s2,restart,append,pn,x_xla,x_csl,x_csr);
7875
7876 #ifdef DEBUG
7877 if (deblog) {
7878 debug(F111,"ftp get rc",s,rc);
7879 debug(F111,"ftp get ftp_timed_out",s,ftp_timed_out);
7880 debug(F111,"ftp get cancelfile",s,cancelfile);
7881 debug(F111,"ftp get cancelgroup",s,cancelgroup);
7882 debug(F111,"ftp get renaming",s,renaming);
7883 debug(F111,"ftp get moving",s,moving);
7884 }
7885 #endif /* DEBUG */
7886 }
7887 if (rc > -1) {
7888 good++;
7889 status = 1;
7890 if (!cancelfile) {
7891 if (deleting) { /* GET /DELETE (source file) */
7892 rc =
7893 (ftpcmd("DELE",s,x_csl,x_csr,ftp_vbm) == REPLY_COMPLETE)
7894 ? 1 : -1;
7895 tlog(F110, (rc > -1) ?
7896 " deleted" : " failed to delete", s, 0);
7897 }
7898 if (renaming && rcv_rename && !toscreen) {
7899 char *p; /* Rename downloaded file */
7900 #ifndef NOSPL
7901 char tmpbuf[CKMAXPATH+1];
7902 int n;
7903 n = CKMAXPATH;
7904 p = tmpbuf;
7905 debug(F111,"ftp get /rename",rcv_rename,0);
7906 zzstring(rcv_rename,&p,&n);
7907 debug(F111,"ftp get /rename",rcv_rename,0);
7908 p = tmpbuf;
7909 #else
7910 p = rcv_rename;
7911 #endif /* NOSPL */
7912 rc = (zrename(s2,p) < 0) ? -1 : 1;
7913 debug(F111,"doftpget /RENAME zrename",p,rc);
7914 tlog(F110, (rc > -1) ?
7915 " renamed to" :
7916 " failed to rename to",
7917 p,
7918 0
7919 );
7920 } else if (moving && rcv_move && !toscreen) {
7921 char *p; /* Move downloaded file */
7922 #ifndef NOSPL
7923 char tmpbuf[CKMAXPATH+1];
7924 int n;
7925 n = TMPBUFSIZ;
7926 p = tmpbuf;
7927 debug(F111,"ftp get /move-to",rcv_move,0);
7928 zzstring(rcv_move,&p,&n);
7929 p = tmpbuf;
7930 #else
7931 p = rcv_move;
7932 #endif /* NOSPL */
7933 debug(F111,"ftp get /move-to",p,0);
7934 rc = (zrename(s2,p) < 0) ? -1 : 1;
7935 debug(F111,"doftpget /MOVE zrename",p,rc);
7936 tlog(F110, (rc > -1) ?
7937 " moved to" : " failed to move to", p, 0);
7938 }
7939 if (pv[SND_SRN].ival > 0 && pv[SND_SRN].sval) {
7940 char * s = pv[SND_SRN].sval;
7941 char * srvrn = pv[SND_SRN].sval;
7942 char tmpbuf[CKMAXPATH+1];
7943 #ifndef NOSPL
7944 int y; /* Pass it thru the evaluator */
7945 extern int cmd_quoting; /* for \v(filename) */
7946 debug(F111,"ftp get srv_renam",s,1);
7947
7948 if (cmd_quoting) {
7949 y = CKMAXPATH;
7950 s = (char *)tmpbuf;
7951 zzstring(srvrn,&s,&y);
7952 s = (char *)tmpbuf;
7953 }
7954 #endif /* NOSPL */
7955 debug(F111,"ftp get srv_renam",s,1);
7956 if (s) if (*s) {
7957 int x;
7958 x = ftp_rename(s2,s);
7959 debug(F111,"ftp get ftp_rename",s2,x);
7960 tlog(F110, (x > 0) ?
7961 " renamed source file to" :
7962 " failed to rename source file to",
7963 s,
7964 0
7965 );
7966 if (x < 1)
7967 return(-1);
7968 }
7969 }
7970 }
7971 }
7972 if (cancelfile)
7973 continue;
7974 if (rc < 0) {
7975 ftp_fai++;
7976 #ifdef FTP_TIMEOUT
7977 debug(F101,"ftp get ftp_timed_out","",ftp_timed_out);
7978 if (ftp_timed_out) {
7979 status = 0;
7980 ftscreen(SCR_EM,0,(CK_OFF_T)0,"GET timed out");
7981 }
7982 #endif /* FTP_TIMEOUT */
7983 if (geterror) {
7984 status = 0;
7985 ftscreen(SCR_EM,0,(CK_OFF_T)0,"Fatal download error");
7986 done++;
7987 }
7988 }
7989 }
7990 #ifdef DEBUG
7991 if (deblog) {
7992 debug(F101,"ftp get status","",status);
7993 debug(F101,"ftp get cancelgroup","",cancelgroup);
7994 debug(F101,"ftp get cancelfile","",cancelfile);
7995 debug(F101,"ftp get selected","",selected);
7996 debug(F101,"ftp get good","",good);
7997 }
7998 #endif /* DEBUG */
7999
8000 if (selected == 0) { /* No files met selection criteria */
8001 status = 1; /* which is a kind of success. */
8002 } else if (status > 0) { /* Some files were selected */
8003 if (cancelgroup) /* but MGET was canceled */
8004 status = 0; /* so MGET failed */
8005 else if (cancelfile && good < 1) /* If file was canceled */
8006 status = 0; /* MGET failed if it got no files */
8007 }
8008 success = status;
8009 x = success;
8010 debug(F101,"ftp get success","",success);
8011
8012 xgetx:
8013 pipesend = pipesave; /* Restore global pipe selection */
8014 if (fp_nml) { /* Close /NAMELIST */
8015 if (fp_nml != stdout)
8016 fclose(fp_nml);
8017 fp_nml = NULL;
8018 }
8019 if (
8020 #ifdef COMMENT
8021 x > -1
8022 #else
8023 success
8024 #endif /* COMMENT */
8025 ) { /* Download successful */
8026 #ifdef GFTIMER
8027 t1 = gmstimer(); /* End time */
8028 sec = (CKFLOAT)((CKFLOAT)(t1 - t0) / 1000.0); /* Stats */
8029 if (!sec) sec = 0.001;
8030 fptsecs = sec;
8031 #else
8032 sec = (t1 - t0) / 1000;
8033 if (!sec) sec = 1;
8034 #endif /* GFTIMER */
8035 tfcps = (long) (tfc / sec);
8036 tsecs = (int)sec;
8037 lastxfer = W_FTP|W_RECV;
8038 xferstat = success;
8039 }
8040 if (dpyactive)
8041 ftscreen(success > 0 ? SCR_TC : SCR_CW, 0, (CK_OFF_T)0, "");
8042 #ifdef CK_TMPDIR
8043 if (f_tmpdir) { /* If we changed to download dir */
8044 zchdir((char *) savdir); /* Go back where we came from */
8045 f_tmpdir = 0;
8046 }
8047 #endif /* CK_TMPDIR */
8048
8049 for (i = 0; i <= SND_MAX; i++) { /* Free malloc'd memory */
8050 if (pv[i].sval)
8051 free(pv[i].sval);
8052 }
8053 for (i = 0; i < mgetn; i++) /* MGET list too */
8054 makestr(&(mgetlist[i]),NULL);
8055
8056 if (cancelgroup) /* Clear temp-file stack */
8057 mlsreset();
8058
8059 ftreset(); /* Undo switch effects */
8060 dpyactive = 0;
8061 return(x);
8062 }
8063
8064 static struct keytab ftprmt[] = {
8065 { "cd", XZCWD, 0 },
8066 { "cdup", XZCDU, 0 },
8067 { "cwd", XZCWD, CM_INV },
8068 { "delete", XZDEL, 0 },
8069 { "directory", XZDIR, 0 },
8070 { "exit", XZXIT, 0 },
8071 { "help", XZHLP, 0 },
8072 { "login", XZLGI, 0 },
8073 { "logout", XZLGO, 0 },
8074 { "mkdir", XZMKD, 0 },
8075 { "pwd", XZPWD, 0 },
8076 { "rename", XZREN, 0 },
8077 { "rmdir", XZRMD, 0 },
8078 { "type", XZTYP, 0 },
8079 { "", 0, 0 }
8080 };
8081 static int nftprmt = (sizeof(ftprmt) / sizeof(struct keytab)) - 1;
8082
8083 int
doftpsite()8084 doftpsite() { /* Send a SITE command */
8085 int reply;
8086 char * s;
8087 int lcs = -1, rcs = -1;
8088 int save_vbm = ftp_vbm;
8089
8090 #ifndef NOCSETS
8091 if (ftp_xla) {
8092 lcs = ftp_csl;
8093 if (lcs < 0) lcs = fcharset;
8094 rcs = ftp_csx;
8095 if (rcs < 0) rcs = ftp_csr;
8096 }
8097 #endif /* NOCSETS */
8098 if ((x = cmtxt("Command", "", &s, xxstring)) < 0)
8099 return(x);
8100 CHECKCONN();
8101 ckstrncpy(line,s,LINBUFSIZ);
8102 if (testing) printf(" ftp site \"%s\"...\n",line);
8103 if (!ftp_vbm)
8104 ftp_vbm = !ckstrcmp("HELP",line,4,0);
8105 if ((reply = ftpcmd("SITE",line,lcs,rcs,ftp_vbm)) == REPLY_PRELIM) {
8106 do {
8107 reply = getreply(0,lcs,rcs,ftp_vbm,0);
8108 } while (reply == REPLY_PRELIM);
8109 }
8110 ftp_vbm = save_vbm;
8111 return(success = (reply == REPLY_COMPLETE));
8112 }
8113
8114
8115 int
dosetftppsv()8116 dosetftppsv() { /* Passive mode */
8117 x = seton(&ftp_psv);
8118 if (x > 0) passivemode = ftp_psv;
8119 return(x);
8120 }
8121
8122 /* d o f t p r m t -- Parse and execute REMOTE commands */
8123
8124 int
doftprmt(cx,who)8125 doftprmt(cx,who) int cx, who; { /* who == 1 for ftp, 0 for kermit */
8126 /* cx == 0 means REMOTE */
8127 /* cx != 0 is a XZxxx value */
8128 char * s;
8129
8130 if (who != 0)
8131 return(0);
8132
8133 if (cx == 0) {
8134 if ((x = cmkey(ftprmt,nftprmt,"","",xxstring)) < 0)
8135 return(x);
8136 cx = x;
8137 }
8138 switch (cx) {
8139 case XZCDU: /* CDUP */
8140 if ((x = cmcfm()) < 0) return(x);
8141 return(doftpcdup());
8142
8143 case XZCWD: /* RCD */
8144 if ((x = cmtxt("Remote directory", "", &s, xxstring)) < 0)
8145 return(x);
8146 ckstrncpy(line,s,LINBUFSIZ);
8147 s = brstrip(line);
8148 return(doftpcwd(s,1));
8149 case XZPWD: /* RPWD */
8150 return(doftppwd());
8151 case XZDEL: /* RDEL */
8152 return(doftpget(FTP_MDE,1));
8153 case XZDIR: /* RDIR */
8154 return(doftpdir(FTP_DIR));
8155 case XZHLP: /* RHELP */
8156 return(doftpxhlp());
8157 case XZMKD: /* RMKDIR */
8158 return(doftpmkd());
8159 case XZREN: /* RRENAME */
8160 return(doftpren());
8161 case XZRMD: /* RRMDIR */
8162 return(doftprmd());
8163 case XZLGO: /* LOGOUT */
8164 return(doftpres());
8165 case XZXIT: /* EXIT */
8166 return(ftpbye());
8167 }
8168 printf("?Not usable with FTP - \"%s\"\n", atmbuf);
8169 return(-9);
8170 }
8171
8172 int
doxftp()8173 doxftp() { /* Command parser for built-in FTP */
8174 int cx, n;
8175 struct FDB kw, fl;
8176 char * s;
8177 int usetls = 0;
8178 int lcs = -1, rcs = -1;
8179
8180 #ifndef NOCSETS
8181 if (ftp_xla) {
8182 lcs = ftp_csl;
8183 if (lcs < 0) lcs = fcharset;
8184 rcs = ftp_csx;
8185 if (rcs < 0) rcs = ftp_csr;
8186 }
8187 #endif /* NOCSETS */
8188
8189 if (inserver) /* FTP not allowed in IKSD. */
8190 return(-2);
8191
8192 if (g_ftp_typ > -1) { /* Restore TYPE if saved */
8193 ftp_typ = g_ftp_typ;
8194 /* g_ftp_typ = -1; */
8195 }
8196 #ifdef COMMENT
8197 /*
8198 We'll set the collision action locally in doftpget() based on whether
8199 ftp_fnc was ever set to a value. if not, we'll use the fncact value.
8200 */
8201 if (ftp_fnc < 0) /* Inherit global collision action */
8202 ftp_fnc = fncact; /* if none specified for FTP */
8203 #endif /* COMMENT */
8204
8205 /* Restore global verbose mode */
8206 if (ftp_deb)
8207 ftp_vbm = 1;
8208 else if (quiet)
8209 ftp_vbm = 0;
8210 else
8211 ftp_vbm = ftp_vbx;
8212
8213 ftp_dates &= 1; /* Undo any previous /UPDATE switch */
8214
8215 dpyactive = 0; /* Reset global transfer-active flag */
8216 printlines = 0; /* Reset printlines */
8217
8218 if (fp_nml) { /* Reset /NAMELIST */
8219 if (fp_nml != stdout)
8220 fclose(fp_nml);
8221 fp_nml = NULL;
8222 }
8223 makestr(&ftp_nml,NULL);
8224
8225 cmfdbi(&kw, /* First FDB - commands */
8226 _CMKEY, /* fcode */
8227 "Hostname; or FTP command", /* help */
8228 "", /* default */
8229 "", /* addtl string data */
8230 nftpcmd, /* addtl numeric data 1: tbl size */
8231 0, /* addtl numeric data 2: none */
8232 xxstring, /* Processing function */
8233 ftpcmdtab, /* Keyword table */
8234 &fl /* Pointer to next FDB */
8235 );
8236 cmfdbi(&fl, /* A host name or address */
8237 _CMFLD, /* fcode */
8238 "Hostname or address", /* help */
8239 "", /* default */
8240 "", /* addtl string data */
8241 0, /* addtl numeric data 1 */
8242 0, /* addtl numeric data 2 */
8243 xxstring,
8244 NULL,
8245 NULL
8246 );
8247 x = cmfdb(&kw); /* Parse a hostname or a keyword */
8248 if (x == -3) {
8249 printf("?ftp what? \"help ftp\" for hints\n");
8250 return(-9);
8251 }
8252 if (x < 0)
8253 return(x);
8254 if (cmresult.fcode == _CMFLD) { /* If hostname */
8255 return(openftp(cmresult.sresult,0)); /* go open the connection */
8256 } else {
8257 cx = cmresult.nresult;
8258 }
8259 switch (cx) {
8260 case FTP_ACC: /* ACCOUNT */
8261 if ((x = cmtxt("Remote account", "", &s, xxstring)) < 0)
8262 return(x);
8263 CHECKCONN();
8264 makestr(&ftp_acc,s);
8265 if (testing)
8266 printf(" ftp account: \"%s\"\n",ftp_acc);
8267 success = (ftpcmd("ACCT",ftp_acc,-1,-1,ftp_vbm) == REPLY_COMPLETE);
8268 return(success);
8269
8270 case FTP_GUP: /* Go UP */
8271 if ((x = cmcfm()) < 0) return(x);
8272 CHECKCONN();
8273 if (testing) printf(" ftp cd: \"(up)\"\n");
8274 return(success = doftpcdup());
8275
8276 case FTP_CWD: /* CD */
8277 if ((x = cmtxt("Remote directory", "", &s, xxstring)) < 0)
8278 return(x);
8279 CHECKCONN();
8280 ckstrncpy(line,s,LINBUFSIZ);
8281 if (testing)
8282 printf(" ftp cd: \"%s\"\n", line);
8283 return(success = doftpcwd(line,1));
8284
8285 case FTP_CHM: /* CHMOD */
8286 if ((x = cmfld("Permissions or protection code","",&s,xxstring)) < 0)
8287 return(x);
8288 ckstrncpy(tmpbuf,s,TMPBUFSIZ);
8289 if ((x = cmtxt("Remote filename", "", &s, xxstring)) < 0)
8290 return(x);
8291 CHECKCONN();
8292 ckmakmsg(ftpcmdbuf,FTP_BUFSIZ,tmpbuf," ",s,NULL);
8293 if (testing)
8294 printf(" ftp chmod: %s\n",ftpcmdbuf);
8295 success =
8296 (ftpcmd("SITE CHMOD",ftpcmdbuf,lcs,rcs,ftp_vbm) == REPLY_COMPLETE);
8297 return(success);
8298
8299 case FTP_CLS: /* CLOSE FTP connection */
8300 if ((y = cmcfm()) < 0)
8301 return(y);
8302 CHECKCONN();
8303 if (testing)
8304 printf(" ftp closing...\n");
8305 ftpclose();
8306 return(success = 1);
8307
8308 case FTP_DIR: /* DIRECTORY of remote files */
8309 case FTP_VDI:
8310 return(doftpdir(cx));
8311
8312 case FTP_GET: /* GET a remote file */
8313 case FTP_RGE: /* REGET */
8314 case FTP_MGE: /* MGET */
8315 case FTP_MDE: /* MDELETE */
8316 return(doftpget(cx,1));
8317
8318 case FTP_IDL: /* IDLE */
8319 if ((x = cmnum("Number of seconds","-1",10,&z,xxstring)) < 0)
8320 return(x);
8321 if ((y = cmcfm()) < 0)
8322 return(y);
8323 CHECKCONN();
8324 if (z < 0) { /* Display idle timeout */
8325 if (testing)
8326 printf(" ftp query idle timeout...\n");
8327 success = (ftpcmd("SITE IDLE",NULL,0,0,1) == REPLY_COMPLETE);
8328 } else { /* Set idle timeout */
8329 if (testing)
8330 printf(" ftp idle timeout set: %d...\n",z);
8331 success =
8332 (ftpcmd("SITE IDLE",ckitoa(z),0,0,1) == REPLY_COMPLETE);
8333 }
8334 return(success);
8335
8336 case FTP_MKD: /* MKDIR */
8337 return(doftpmkd());
8338
8339 case FTP_MOD: /* MODTIME */
8340 if ((x = cmtxt("Remote filename", "", &s, xxstring)) < 0)
8341 return(x);
8342 CHECKCONN();
8343 ckstrncpy(line,s,LINBUFSIZ);
8344 if (testing)
8345 printf(" ftp modtime \"%s\"...\n",line);
8346 success = 0;
8347 if (ftpcmd("MDTM",line,lcs,rcs,ftp_vbm) == REPLY_COMPLETE) {
8348 success = 1;
8349 mdtmok = 1;
8350 if (!quiet) {
8351 int flag = 0;
8352 char c, * s;
8353 struct tm tmremote;
8354
8355 bzero((char *)&tmremote, sizeof(struct tm));
8356 s = ftp_reply_str;
8357 while ((c = *s++)) {
8358 if (c == SP) {
8359 flag++;
8360 break;
8361 }
8362 }
8363 if (flag) {
8364 if (sscanf(s, "%04d%02d%02d%02d%02d%02d",
8365 &tmremote.tm_year,
8366 &tmremote.tm_mon,
8367 &tmremote.tm_mday,
8368 &tmremote.tm_hour,
8369 &tmremote.tm_min,
8370 &tmremote.tm_sec
8371 ) == 6) {
8372 printf(" %s %04d-%02d-%02d %02d:%02d:%02d GMT\n",
8373 line,
8374 tmremote.tm_year,
8375 tmremote.tm_mon,
8376 tmremote.tm_mday,
8377 tmremote.tm_hour,
8378 tmremote.tm_min,
8379 tmremote.tm_sec
8380 );
8381 } else {
8382 success = 0;
8383 }
8384 }
8385 }
8386 }
8387 return(success);
8388
8389 case FTP_OPN: /* OPEN connection */
8390 #ifdef COMMENT
8391 x = cmfld("IP hostname or address","",&s,xxstring);
8392 if (x < 0) {
8393 success = 0;
8394 return(x);
8395 }
8396 ckstrncpy(line,s,LINBUFSIZ);
8397 s = line;
8398 return(openftp(s,0));
8399 #else
8400 { /* OPEN connection */
8401 char name[TTNAMLEN+1], *p;
8402 extern int network;
8403 extern char ttname[];
8404 if (network) /* If we have a current connection */
8405 ckstrncpy(name,ttname,LINBUFSIZ); /* get the host name */
8406 else
8407 *name = '\0'; /* as default host */
8408 for (p = name; *p; p++) /* Remove ":service" from end. */
8409 if (*p == ':') { *p = '\0'; break; }
8410 #ifndef USETLSTAB
8411 x = cmfld("IP hostname or address",name,&s,xxstring);
8412 #else
8413 cmfdbi(&kw, /* First FDB - commands */
8414 _CMKEY, /* fcode */
8415 "Hostname or switch", /* help */
8416 "", /* default */
8417 "", /* addtl string data */
8418 ntlstab, /* addtl numeric data 1: tbl size */
8419 0, /* addtl numeric data 2: none */
8420 xxstring, /* Processing function */
8421 tlstab, /* Keyword table */
8422 &fl /* Pointer to next FDB */
8423 );
8424 cmfdbi(&fl, /* A host name or address */
8425 _CMFLD, /* fcode */
8426 "Hostname or address", /* help */
8427 "", /* default */
8428 "", /* addtl string data */
8429 0, /* addtl numeric data 1 */
8430 0, /* addtl numeric data 2 */
8431 xxstring,
8432 NULL,
8433 NULL
8434 );
8435
8436 for (n = 0;; n++) {
8437 x = cmfdb(&kw); /* Parse a hostname or a keyword */
8438 if (x == -3) {
8439 printf("?ftp open what? \"help ftp\" for hints\n");
8440 return(-9);
8441 }
8442 if (x < 0)
8443 break;
8444 if (cmresult.fcode == _CMFLD) { /* Hostname */
8445 s = cmresult.sresult;
8446 break;
8447 } else if (cmresult.nresult == OPN_TLS) {
8448 usetls = 1;
8449 }
8450 }
8451 #endif /* USETLSTAB */
8452 if (x < 0) {
8453 success = 0;
8454 return(x);
8455 }
8456 ckstrncpy(line,s,LINBUFSIZ);
8457 s = line;
8458 return(openftp(s,usetls));
8459 }
8460 #endif /* COMMENT */
8461
8462 case FTP_PUT: /* PUT */
8463 case FTP_MPU: /* MPUT */
8464 case FTP_APP: /* APPEND */
8465 case FTP_REP: /* REPUT */
8466 return(doftpput(cx,1));
8467
8468 case FTP_PWD: /* PWD */
8469 x = doftppwd();
8470 if (x > -1) success = x;
8471 return(x);
8472
8473 case FTP_REN: /* RENAME */
8474 return(doftpren());
8475
8476 case FTP_RES: /* RESET */
8477 return(doftpres());
8478
8479 case FTP_HLP: /* (remote) HELP */
8480 return(doftpxhlp());
8481
8482 case FTP_RMD: /* RMDIR */
8483 return(doftprmd());
8484
8485 case FTP_STA: /* STATUS */
8486 if ((x = cmtxt("Command", "", &s, xxstring)) < 0)
8487 return(x);
8488 CHECKCONN();
8489 ckstrncpy(line,s,LINBUFSIZ);
8490 if (testing) printf(" ftp status \"%s\"...\n",line);
8491 success = (ftpcmd("STAT",line,lcs,rcs,1) == REPLY_COMPLETE);
8492 return(success);
8493
8494 case FTP_SIT: { /* SITE */
8495 return(doftpsite());
8496 }
8497
8498 case FTP_SIZ: /* (ask for) SIZE */
8499 if ((x = cmtxt("Remote filename", "", &s, xxstring)) < 0)
8500 return(x);
8501 CHECKCONN();
8502 ckstrncpy(line,s,LINBUFSIZ);
8503 if (testing)
8504 printf(" ftp size \"%s\"...\n",line);
8505 success = (ftpcmd("SIZE",line,lcs,rcs,1) == REPLY_COMPLETE);
8506 if (success)
8507 sizeok = 1;
8508 return(success);
8509
8510 case FTP_SYS: /* Ask for server's SYSTEM type */
8511 if ((x = cmcfm()) < 0) return(x);
8512 CHECKCONN();
8513 if (testing)
8514 printf(" ftp system...\n");
8515 success = (ftpcmd("SYST",NULL,0,0,1) == REPLY_COMPLETE);
8516 return(success);
8517
8518 case FTP_UMA: /* Set/query UMASK */
8519 if ((x = cmfld("Umask to set or nothing to query","",&s,xxstring)) < 0)
8520 if (x != -3)
8521 return(x);
8522 ckstrncpy(tmpbuf,s,TMPBUFSIZ);
8523 if ((x = cmcfm()) < 0) return(x);
8524 CHECKCONN();
8525 if (testing) {
8526 if (tmpbuf[0])
8527 printf(" ftp umask \"%s\"...\n",tmpbuf);
8528 else
8529 printf(" ftp query umask...\n");
8530 }
8531 success = ftp_umask(tmpbuf);
8532 return(success);
8533
8534 case FTP_USR:
8535 return(doftpusr());
8536
8537 case FTP_QUO:
8538 if ((x = cmtxt("FTP protocol command", "", &s, xxstring)) < 0)
8539 return(x);
8540 CHECKCONN();
8541 success = (ftpcmd(s,NULL,0,0,ftp_vbm) == REPLY_COMPLETE);
8542 return(success);
8543
8544 case FTP_TYP: /* Type */
8545 if ((x = cmkey(ftptyp,nftptyp,"","",xxstring)) < 0)
8546 return(x);
8547 if ((y = cmcfm()) < 0) return(y);
8548 CHECKCONN();
8549 ftp_typ = x;
8550 g_ftp_typ = x;
8551 tenex = (ftp_typ == FTT_TEN);
8552 changetype(ftp_typ,ftp_vbm);
8553 return(1);
8554
8555 case FTP_CHK: /* Check if remote file(s) exist(s) */
8556 if ((x = cmtxt("remote filename", "", &s, xxstring)) < 0)
8557 return(x);
8558 CHECKCONN();
8559 success = remote_files(1,(CHAR *)s,(CHAR *)s,0) ? 1 : 0;
8560 return(success);
8561
8562 case FTP_FEA: /* RFC2389 */
8563 if ((y = cmcfm()) < 0)
8564 return(y);
8565 CHECKCONN();
8566 success = (ftpcmd("FEAT",NULL,0,0,1) == REPLY_COMPLETE);
8567 if (success) {
8568 if (sfttab[0] > 0) {
8569 ftp_aut = sfttab[SFT_AUTH];
8570 sizeok = sfttab[SFT_SIZE];
8571 mdtmok = sfttab[SFT_MDTM];
8572 mlstok = sfttab[SFT_MLST];
8573 }
8574 }
8575 return(success);
8576
8577 case FTP_OPT: /* RFC2389 */
8578 /* Perhaps this should be a keyword list... */
8579 if ((x = cmfld("FTP command","",&s,xxstring)) < 0)
8580 return(x);
8581 CHECKCONN();
8582 ckstrncpy(line,s,LINBUFSIZ);
8583 if ((x = cmtxt("Options for this command", "", &s, xxstring)) < 0)
8584 return(x);
8585 success = (ftpcmd("OPTS",line,lcs,rcs,ftp_vbm) == REPLY_COMPLETE);
8586 return(success);
8587
8588 case FTP_ENA: /* FTP ENABLE */
8589 case FTP_DIS: /* FTP DISABLE */
8590 if ((x = cmkey(ftpenatab,nftpena,"","",xxstring)) < 0)
8591 return(x);
8592 if ((y = cmcfm()) < 0) return(y);
8593 switch (x) {
8594 case ENA_AUTH: /* OK to use autoauthentication */
8595 ftp_aut = (cx == FTP_ENA) ? 1 : 0;
8596 sfttab[SFT_AUTH] = ftp_aut;
8597 break;
8598 case ENA_FEAT: /* OK to send FEAT command */
8599 featok = (cx == FTP_ENA) ? 1 : 0;
8600 break;
8601 case ENA_MLST: /* OK to use MLST/MLSD */
8602 mlstok = (cx == FTP_ENA) ? 1 : 0;
8603 sfttab[SFT_MLST] = mlstok;
8604 break;
8605 case ENA_MDTM: /* OK to use MDTM */
8606 mdtmok = (cx == FTP_ENA) ? 1 : 0;
8607 sfttab[SFT_MDTM] = mdtmok;
8608 break;
8609 case ENA_SIZE: /* OK to use SIZE */
8610 sizeok = (cx == FTP_ENA) ? 1 : 0;
8611 sfttab[SFT_SIZE] = sizeok;
8612 break;
8613 }
8614 return(success = 1);
8615 }
8616 return(-2);
8617 }
8618
8619 #ifndef NOSHOW
8620 static char *
shopl(x)8621 shopl(x) int x; {
8622 switch (x) {
8623 case FPL_CLR: return("clear");
8624 case FPL_PRV: return("private");
8625 case FPL_SAF: return("safe");
8626 case 0: return("(not set)");
8627 default: return("(unknown)");
8628 }
8629 }
8630
8631 int
shoftp(brief)8632 shoftp(brief) int brief; {
8633 char * s = "?";
8634 int n, x;
8635
8636 if (g_ftp_typ > -1) { /* Restore TYPE if saved */
8637 ftp_typ = g_ftp_typ;
8638 /* g_ftp_typ = -1; */
8639 }
8640 printf("\n");
8641 printf("FTP connection: %s\n",connected ?
8642 ftp_host :
8643 "(none)"
8644 );
8645 n = 2;
8646 if (connected) {
8647 n++;
8648 printf("FTP server type: %s\n",
8649 ftp_srvtyp[0] ? ftp_srvtyp : "(unknown)");
8650 }
8651 if (loggedin)
8652 printf("Logged in as: %s\n",
8653 strval(ftp_logname,"(unknown)"));
8654 else
8655 printf("Not logged in\n");
8656 n++;
8657 if (brief) return(0);
8658
8659 printf("\nSET FTP values:\n\n");
8660 n += 3;
8661
8662 printf(" ftp anonymous-password: %s\n",
8663 ftp_apw ? ftp_apw : "(default)"
8664 );
8665 printf(" ftp auto-login: %s\n",showoff(ftp_log));
8666 printf(" ftp auto-authentication: %s\n",showoff(ftp_aut));
8667 switch (ftp_typ) {
8668 case FTT_ASC: s = "text"; break;
8669 case FTT_BIN: s = "binary"; break;
8670 case FTT_TEN: s = "tenex"; break;
8671 }
8672 #ifdef FTP_TIMEOUT
8673 printf(" ftp timeout: %ld\n",ftp_timeout);
8674 #endif /* FTP_TIMEOUT */
8675 printf(" ftp type: %s\n",s);
8676 printf(" ftp get-filetype-switching: %s\n",showoff(get_auto));
8677 printf(" ftp dates: %s\n",showoff(ftp_dates));
8678 printf(" ftp error-action: %s\n",ftp_err ? "quit":"proceed");
8679 printf(" ftp filenames: %s\n",
8680 ftp_cnv == CNV_AUTO ? "auto" : (ftp_cnv ? "converted" : "literal")
8681 );
8682 printf(" ftp debug %s\n",showoff(ftp_deb));
8683
8684 printf(" ftp passive-mode: %s\n",showoff(ftp_psv));
8685 printf(" ftp permissions: %s\n",showooa(ftp_prm));
8686 printf(" ftp verbose-mode: %s\n",showoff(ftp_vbx));
8687 printf(" ftp send-port-commands: %s\n",showoff(ftp_psv));
8688 printf(" ftp unique-server-names: %s\n",showoff(ftp_usn));
8689 #ifdef COMMENT
8690 /* See note in doxftp() */
8691 if (ftp_fnc < 0)
8692 ftp_fnc = fncact;
8693 #endif /* COMMENT */
8694 printf(" ftp collision: %s\n",
8695 fncnam[ftp_fnc > -1 ? ftp_fnc : fncact]);
8696 printf(" ftp server-time-offset: %s\n",
8697 fts_sto ? fts_sto : "(none)");
8698 n += 15;
8699
8700 #ifndef NOCSETS
8701 printf(" ftp character-set-translation: %s\n",showoff(ftp_xla));
8702 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8703
8704 printf(" ftp server-character-set: %s\n",fcsinfo[ftp_csr].keyword);
8705 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8706
8707 printf(" file character-set: %s\n",fcsinfo[fcharset].keyword);
8708 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8709 #endif /* NOCSETS */
8710
8711 x = ftp_dis;
8712 if (x < 0)
8713 x = fdispla;
8714 switch (x) {
8715 case XYFD_N: s = "none"; break;
8716 case XYFD_R: s = "serial"; break;
8717 case XYFD_C: s = "fullscreen"; break;
8718 case XYFD_S: s = "crt"; break;
8719 case XYFD_B: s = "brief"; break;
8720 }
8721 printf(" ftp display: %s\n",s);
8722 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8723
8724 if (mlstok || featok || mdtmok || sizeok || ftp_aut) {
8725 printf(" enabled: ");
8726 if (ftp_aut) printf(" AUTH");
8727 if (featok) printf(" FEAT");
8728 if (mdtmok) printf(" MDTM");
8729 if (mlstok) printf(" MLST");
8730 if (sizeok) printf(" SIZE");
8731 printf("\n");
8732 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8733 }
8734 if (!mlstok || !featok || !mdtmok || !sizeok || !ftp_aut) {
8735 printf(" disabled: ");
8736 if (!ftp_aut) printf(" AUTH");
8737 if (!featok) printf(" FEAT");
8738 if (!mdtmok) printf(" MDTM");
8739 if (!mlstok) printf(" MLST");
8740 if (!sizeok) printf(" SIZE");
8741 printf("\n");
8742 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8743 }
8744 switch (ftpget) {
8745 case 0: s = "kermit"; break;
8746 case 1: s = "ftp"; break;
8747 case 2: s = "auto"; break;
8748 default: s = "?";
8749 }
8750 printf(" get-put-remote: %s\n",s);
8751 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8752
8753 printf("\n");
8754 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8755
8756 #ifdef FTP_SECURITY
8757 printf("Available security methods: ");
8758 #ifdef FTP_GSSAPI
8759 printf("GSSAPI ");
8760 #endif /* FTP_GSSAPI */
8761 #ifdef FTP_KRB4
8762 printf("Kerberos4 ");
8763 #endif /* FTP_KRB4 */
8764 #ifdef FTP_SRP
8765 printf("SRP ");
8766 #endif /* FTP_SRP */
8767 #ifdef FTP_SSL
8768 printf("SSL ");
8769 #endif /* FTP_SSL */
8770
8771 n++;
8772 printf("\n\n");
8773 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8774 printf(" ftp authtype: %s\n",strval(auth_type,NULL));
8775 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8776 printf(" ftp auto-encryption: %s\n",showoff(ftp_cry));
8777 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8778 printf(" ftp credential-forwarding: %s\n",showoff(ftp_cfw));
8779 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8780 printf(" ftp command-protection-level: %s\n",shopl(ftp_cpl));
8781 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8782 printf(" ftp data-protection-level: %s\n",shopl(ftp_dpl));
8783 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8784 printf(" ftp secure proxy: %s\n",shopl(ssl_ftp_proxy));
8785 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8786 #else
8787 printf("Available security methods: (none)\n");
8788 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8789 #endif /* FTP_SECURITY */
8790
8791 if (n <= cmd_rows - 3)
8792 printf("\n");
8793 return(0);
8794 }
8795 #endif /* NOSHOW */
8796
8797 #ifndef NOHELP
8798 /* FTP HELP text strings */
8799
8800 static char * fhs_ftp[] = {
8801 "Syntax: FTP subcommand [ operands ]",
8802 " Makes an FTP connection, or sends a command to the FTP server.",
8803 " To see a list of available FTP subcommands, type \"ftp ?\".",
8804 " and then use HELP FTP xxx to get help about subcommand xxx.",
8805 " Also see HELP SET FTP, HELP SET GET-PUT-REMOTE, and HELP FIREWALL.",
8806 ""
8807 };
8808
8809 static char * fhs_acc[] = { /* ACCOUNT */
8810 "Syntax: FTP ACCOUNT text",
8811 " Sends an account designator to an FTP server that needs one.",
8812 " Most FTP servers do not use accounts; some use them for other",
8813 " other purposes, such as disk-access passwords.",
8814 ""
8815 };
8816 static char * fhs_app[] = { /* APPEND */
8817 "Syntax: FTP APPEND filname",
8818 " Equivalent to [ FTP ] PUT /APPEND. See HELP FTP PUT.",
8819 ""
8820 };
8821 static char * fhs_cls[] = { /* BYE, CLOSE */
8822 "Syntax: [ FTP ] BYE",
8823 " Logs out from the FTP server and closes the FTP connection.",
8824 " Also see HELP SET GET-PUT-REMOTE. Synonym: [ FTP ] CLOSE.",
8825 ""
8826 };
8827 static char * fhs_cwd[] = { /* CD, CWD */
8828 "Syntax: [ FTP ] CD directory",
8829 " Asks the FTP server to change to the given directory.",
8830 " Also see HELP SET GET-PUT-REMOTE. Synonyms: [ FTP ] CWD, RCD, RCWD.",
8831 ""
8832 };
8833 static char * fhs_gup[] = { /* CDUP, UP */
8834 "Syntax: FTP CDUP",
8835 " Asks the FTP server to change to the parent directory of its current",
8836 " directory. Also see HELP SET GET-PUT-REMOTE. Synonym: FTP UP.",
8837 ""
8838 };
8839 static char * fhs_chm[] = { /* CHMOD */
8840 "Syntax: FTP CHMOD filename permissions",
8841 " Asks the FTP server to change the permissions, protection, or mode of",
8842 " the given file. The given permissions must be in the syntax of the",
8843 " the server's file system, e.g. an octal number for UNIX. Also see",
8844 " FTP PUT /PERMISSIONS",
8845 ""
8846 };
8847 static char * fhs_mde[] = { /* DELETE */
8848 "Syntax: FTP DELETE [ switches ] filespec",
8849 " Asks the FTP server to delete the given file or files.",
8850 " Synonym: MDELETE (Kermit makes no distinction between single and",
8851 " multiple file deletion). Optional switches:",
8852 " ",
8853 " /ERROR-ACTION:{PROCEED,QUIT}",
8854 " /EXCEPT:pattern",
8855 " /FILENAMES:{AUTO,CONVERTED,LITERAL}",
8856 " /LARGER-THAN:number",
8857 #ifdef UNIXOROSK
8858 " /NODOTFILES",
8859 #endif /* UNIXOROSK */
8860 " /QUIET",
8861 #ifdef RECURSIVE
8862 " /RECURSIVE (depends on server)",
8863 " /SUBDIRECTORIES",
8864 #endif /* RECURSIVE */
8865 " /SMALLER-THAN:number",
8866 ""
8867 };
8868 static char * fhs_dir[] = { /* DIRECTORY */
8869 "Syntax: FTP DIRECTORY [ filespec ]",
8870 " Asks the server to send a directory listing of the files that match",
8871 " the given filespec, or if none is given, all the files in its current",
8872 " directory. The filespec, including any wildcards, must be in the",
8873 " syntax of the server's file system. Also see HELP SET GET-PUT-REMOTE.",
8874 " Synonym: RDIRECTORY.",
8875 ""
8876 };
8877 static char * fhs_vdi[] = { /* VDIRECTORY */
8878 "Syntax: FTP VDIRECTORY [ filespec ]",
8879 " Asks the server to send a directory listing of the files that match",
8880 " the given filespec, or if none is given, all the files in its current",
8881 " directory. VDIRECTORY is needed for getting verbose directory",
8882 " listings from certain FTP servers, such as on TOPS-20. Try it if",
8883 " FTP DIRECTORY lists only filenames without details.",
8884 ""
8885 };
8886 static char * fhs_fea[] = { /* FEATURES */
8887 "Syntax: FTP FEATURES",
8888 " Asks the FTP server to list its special features. Most FTP servers",
8889 " do not recognize this command.",
8890 ""
8891 };
8892 static char * fhs_mge[] = { /* MGET */
8893 "Syntax: [ FTP ] MGET [ options ] filespec [ filespec [ filespec ... ] ]",
8894 " Download a single file or multiple files. Asks the FTP server to send",
8895 " the given file or files. Also see FTP GET. Optional switches:",
8896 " ",
8897 " /AS-NAME:text",
8898 " Name under which to store incoming file.",
8899 " Pattern required for for multiple files.",
8900 " /BINARY", /* /IMAGE */
8901 " Force binary mode. Synonym: /IMAGE.",
8902 " /COLLISION:{BACKUP,RENAME,UPDATE,DISCARD,APPEND,OVERWRITE}",
8903 " What to do if an incoming file has the same name as an existing file.",
8904
8905 #ifdef PUTPIPE
8906 " /COMMAND",
8907 " Specifies that the as-name is a command to which the incoming file",
8908 " is to be piped as standard input.",
8909 #endif /* PUTPIPE */
8910
8911 #ifdef DOUPDATE
8912 " /DATES-DIFFER",
8913 " Download only those files whose modification date-times differ from",
8914 " those of the corresponding local files, or that do not already",
8915 " exist on the local computer.",
8916 #endif /* DOUPDATE */
8917
8918 " /DELETE",
8919 " Specifies that each file is to be deleted from the server after,",
8920 " and only if, it is successfully downloaded.",
8921 " /ERROR-ACTION:{PROCEED,QUIT}",
8922 " When downloading a group of files, what to do upon failure to",
8923 " transfer a file: quit or proceed to the next one.",
8924 " /EXCEPT:pattern",
8925 " Exception list: don't download any files that match this pattern.",
8926 " See HELP WILDCARD for pattern syntax.",
8927 " /FILENAMES:{AUTOMATIC,CONVERTED,LITERAL}",
8928 " Whether to convert incoming filenames to local syntax.",
8929 #ifdef PIPESEND
8930 #ifndef NOSPL
8931 " /FILTER:command",
8932 " Pass incoming files through the given command.",
8933 #endif /* NOSPL */
8934 #endif /* PIPESEND */
8935 " /LARGER-THAN:number",
8936 " Only download files that are larger than the given number of bytes.",
8937 " /LISTFILE:filename",
8938 " Obtain the list of files to download from the given file.",
8939 #ifndef NOCSETS
8940 " /LOCAL-CHARACTER-SET:name",
8941 " When downloading in text mode and character-set conversion is",
8942 " desired, this specifies the target set.",
8943 #endif /* NOCSETS */
8944 " /MATCH:pattern",
8945 " Specifies a pattern to be used to select filenames locally from the",
8946 " server's list.",
8947 " /MLSD",
8948 " Forces sending of MLSD (rather than NLST) to get the file list.",
8949 #ifdef CK_TMPDIR
8950 " /MOVE-TO:directory",
8951 " Each file that is downloaded is to be moved to the given local",
8952 " directory immediately after, and only if, it has been received",
8953 " successfully.",
8954 #endif /* CK_TMPDIR */
8955 " /NAMELIST:filename",
8956 " Instead of downloading the files, stores the list of files that",
8957 " would be downloaded in the given local file, one filename per line.",
8958 " /NLST",
8959 " Forces sending of NLST (rather than MLSD) to get the file list.",
8960 " /NOBACKUPFILES",
8961 " Don't download any files whose names end with .~<number>~.",
8962 " /NODOTFILES",
8963 " Don't download any files whose names begin with period (.).",
8964 " /QUIET",
8965 " Suppress the file-transfer display.",
8966 #ifdef FTP_RESTART
8967 " /RECOVER", /* /RESTART */
8968 " Resume a download that was previously interrupted from the point of",
8969 " failure. Works only in binary mode. Not supported by all servers.",
8970 " Synonym: /RESTART.",
8971 #endif /* FTP_RESTART */
8972 #ifdef RECURSIVE
8973 " /RECURSIVE", /* /SUBDIRECTORIES */
8974 " Create subdirectories automatically if the server sends files",
8975 " recursively and includes pathnames (most don't).",
8976 #endif /* RECURSIVE */
8977 " /RENAME-TO:text",
8978 " Each file that is downloaded is to be renamed as indicated just,",
8979 " after, and only if, it has arrived successfully.",
8980 #ifndef NOCSETS
8981 " /SERVER-CHARACTER-SET:name",
8982 " When downloading in text mode and character-set conversion is desired"
8983 , " this specifies the original file's character set on the server.",
8984 #endif /* NOCSETS */
8985 " /SERVER-RENAME:text",
8986 " Each server source file is to be renamed on the server as indicated",
8987 " immediately after, but only if, it has arrived successfully.",
8988 " /SMALLER-THAN:number",
8989 " Download only those files smaller than the given number of bytes.",
8990 " /TEXT", /* /ASCII */
8991 " Force text mode. Synonym: /ASCII.",
8992 " /TENEX",
8993 " Force TENEX (TOPS-20) mode (see HELP SET FTP TYPE).",
8994 #ifndef NOCSETS
8995 " /TRANSPARENT",
8996 " When downloading in text mode, do not convert chracter-sets.",
8997 #endif /* NOCSETS */
8998 " /TO-SCREEN",
8999 " The downloaded file is to be displayed on the screen.",
9000 #ifdef DOUPDATE
9001 " /UPDATE",
9002 " Equivalent to /COLLISION:UPDATE. Download only those files that are",
9003 " newer than than their local counterparts, or that do not exist on",
9004 " the local computer.",
9005 #endif /* DOUPDATE */
9006 ""
9007 };
9008 static char * fhs_hlp[] = { /* HELP */
9009 "Syntax: FTP HELP [ command [ subcommand... ] ]",
9010 " Asks the FTP server for help about the given command. First use",
9011 " FTP HELP by itself to get a list of commands, then use HELP FTP xxx",
9012 " to get help for command \"xxx\". Synonyms: REMOTE HELP, RHELP.",
9013 ""
9014 };
9015 static char * fhs_idl[] = { /* IDLE */
9016 "Syntax: FTP IDLE [ number ]",
9017 " If given without a number, this asks the FTP server to tell its",
9018 " current idle-time limit. If given with a number, it asks the server",
9019 " to change its idle-time limit to the given number of seconds.",
9020 ""
9021 };
9022 static char * fhs_usr[] = { /* USER, LOGIN */
9023 "Syntax: FTP USER username [ password [ account ] ]",
9024 " Log in to the FTP server. To be used when connected but not yet",
9025 " logged in, e.g. when SET FTP AUTOLOGIN is OFF or autologin failed.",
9026 " If you omit the password, and one is required by the server, you are",
9027 " prompted for it. If you omit the account, no account is sent.",
9028 " Synonym: FTP LOGIN.",
9029 ""
9030 };
9031 static char * fhs_get[] = { /* GET */
9032 "Syntax: [ FTP ] GET [ options ] filename [ as-name ]",
9033 " Download a single file. Asks the FTP server to send the given file.",
9034 " The optional as-name is the name to store it under when it arrives;",
9035 " if omitted, the file is stored with the name it arrived with, as",
9036 " modified according to the FTP FILENAMES setting or /FILENAMES: switch",
9037 " value. Aside from the file list and as-name, syntax and options are",
9038 " the same as for FTP MGET, which is used for downloading multiple files."
9039 , ""
9040 };
9041 static char * fhs_mkd[] = { /* MKDIR */
9042 "Syntax: FTP MKDIR directory",
9043 " Asks the FTP server to create a directory with the given name,",
9044 " which must be in the syntax of the server's file system. Synonyms:",
9045 " REMOTE MKDIR, RMKDIR.",
9046 ""
9047 };
9048 static char * fhs_mod[] = { /* MODTIME */
9049 "Syntax: FTP MODTIME filename",
9050 " Asks the FTP server to send the modification time of the given file,",
9051 " to be displayed on the screen. The date-time format is all numeric:",
9052 " yyyymmddhhmmssxxx... (where xxx... is 0 or more digits indicating",
9053 " fractions of seconds).",
9054 ""
9055 };
9056 static char * fhs_mpu[] = { /* MPUT */
9057 "Syntax: [ FTP ] MPUT [ switches ] filespec [ filespec [ filespec ... ] ]",
9058 " Uploads files. Sends the given file or files to the FTP server.",
9059 " Also see FTP PUT. Optional switches are:",
9060 " ",
9061 " /AFTER:date-time",
9062 " Uploads only those files newer than the given date-time.",
9063 " HELP DATE for info about date-time formats. Synonym: /SINCE.",
9064 #ifdef PUTARRAY
9065 " /ARRAY:array-designator",
9066 " Tells Kermit to upload the contents of the given array, rather than",
9067 " a file.",
9068 #endif /* PUTARRAY */
9069 " /AS-NAME:text",
9070 " Name under which to send files.",
9071 " Pattern required for for multiple files.",
9072 " /BEFORE:date-time",
9073 " Upload only those files older than the given date-time.",
9074 " /BINARY",
9075 " Force binary mode. Synonym: /IMAGE.",
9076 #ifdef PUTPIPE
9077 " /COMMAND",
9078 " Specifies that the filespec is a command whose standard output is",
9079 " to be sent.",
9080 #endif /* PUTPIPE */
9081
9082 #ifdef COMMENT
9083 #ifdef DOUPDATE
9084 " /DATES-DIFFER",
9085 " Upload only those files whose modification date-times differ from",
9086 " those on the server, or that don't exist on the server at all.",
9087 #endif /* DOUPDATE */
9088 #endif /* COMMENT */
9089
9090 " /DELETE",
9091 " Specifies that each source file is to be deleted after, and only if,",
9092 " it is successfully uploaded.",
9093 " /DOTFILES",
9094 " Include files whose names begin with period (.).",
9095 " /ERROR-ACTION:{PROCEED,QUIT}",
9096 " When uploading a group of files, what to do upon failure to",
9097 " transfer a file: quit or proceed to the next one.",
9098 " /EXCEPT:pattern",
9099 " Exception list: don't upload any files that match this pattern.",
9100 " See HELP WILDCARD for pattern syntax.",
9101 " /FILENAMES:{AUTOMATIC,CONVERTED,LITERAL}",
9102 " Whether to convert outbound filenames to common syntax.",
9103 #ifdef PIPESEND
9104 #ifndef NOSPL
9105 " /FILTER:command",
9106 " Pass outbound files through the given command.",
9107 #endif /* NOSPL */
9108 #endif /* PIPESEND */
9109 #ifdef CKSYMLINK
9110 " /FOLLOWINKS",
9111 " Send files that are pointed to by symbolic links.",
9112 " /NOFOLLOWINKS",
9113 " Skip over symbolic links (default).",
9114 #endif /* CKSYMLINK */
9115 " /LARGER-THAN:number",
9116 " Only upload files that are larger than the given number of bytes.",
9117 " /LISTFILE:filename",
9118 " Obtain the list of files to upload from the given file.",
9119 #ifndef NOCSETS
9120 " /LOCAL-CHARACTER-SET:name",
9121 " When uploading in text mode and character-set conversion is",
9122 " desired, this specifies the source-file character set.",
9123 #endif /* NOCSETS */
9124 #ifdef CK_TMPDIR
9125 " /MOVE-TO:directory",
9126 " Each source file that is uploaded is to be moved to the given local",
9127 " directory when, and only if, the transfer is successful.",
9128 #endif /* CK_TMPDIR */
9129 " /NOBACKUPFILES",
9130 " Don't upload any files whose names end with .~<number>~.",
9131 #ifdef UNIXOROSK
9132 " /NODOTFILES",
9133 " Don't upload any files whose names begin with period (.).",
9134 #endif /* UNIXOROSK */
9135 " /NOT-AFTER:date-time",
9136 " Upload only files that are not newer than the given date-time",
9137 " /NOT-BEFORE:date-time",
9138 " Upload only files that are not older than the given date-time",
9139 #ifdef UNIX
9140 " /PERMISSIONS",
9141 " Ask the server to set the permissions of each file it receives",
9142 " according to the source file's permissions.",
9143 #endif /* UNIX */
9144 " /QUIET",
9145 " Suppress the file-transfer display.",
9146 #ifdef FTP_RESTART
9147 " /RECOVER",
9148 " Resume an upload that was previously interrupted from the point of",
9149 " failure. Synonym: /RESTART.",
9150 #endif /* FTP_RESTART */
9151 #ifdef RECURSIVE
9152 " /RECURSIVE",
9153 " Send files from the given directory and all the directories beneath",
9154 " it. Synonym: /SUBDIRECTORIES.",
9155 #endif /* RECURSIVE */
9156 " /RENAME-TO:text",
9157 " Each source file that is uploaded is to be renamed on the local",
9158 " local computer as indicated when and only if, the transfer completes",
9159 " successfully.",
9160 #ifndef NOCSETS
9161 " /SERVER-CHARACTER-SET:name",
9162 " When uploading in text mode and character-set conversion is desired,",
9163 " this specifies the character set to which the file should be",
9164 " converted for storage on the server.",
9165 #endif /* NOCSETS */
9166 " /SERVER-RENAME:text",
9167 " Each file that is uploaded is to be renamed as indicated on the",
9168 " server after, and only if, if arrives successfully.",
9169 " /SIMULATE",
9170 " Show which files would be sent without actually sending them.",
9171 " /SMALLER-THAN:number",
9172 " Upload only those files smaller than the given number of bytes.",
9173 " /TEXT",
9174 " Force text mode. Synonym: /ASCII.",
9175 " /TENEX",
9176 " Force TENEX (TOPS-20) mode (see HELP SET FTP TYPE).",
9177 #ifndef NOCSETS
9178 " /TRANSPARENT",
9179 " When uploading in text mode, do not convert chracter-sets.",
9180 #endif /* NOCSETS */
9181 " /TYPE:{TEXT,BINARY}",
9182 " Upload only files of the given type.",
9183 #ifdef DOUPDATE
9184 " /UPDATE",
9185 " If a file of the same name exists on the server, upload only if",
9186 " the local file is newer.",
9187 #endif /* DOUPDATE */
9188 " /UNIQUE-SERVER-NAMES",
9189 " Ask the server to compute new names for any incoming file that has",
9190 " the same name as an existing file.",
9191 ""
9192 };
9193 static char * fhs_opn[] = { /* OPEN */
9194 #ifdef CK_SSL
9195 "Syntax: FTP [ OPEN ] [ { /SSL, /TLS } ] hostname [ port ] [ switches ]",
9196 " Opens a connection to the FTP server on the given host. The default",
9197 " TCP port is 21 (990 if SSL/TLS is used), but a different port number",
9198 " can be supplied if necessary. Optional switches are:",
9199 #else /* CK_SSL */
9200 "Syntax: FTP [ OPEN ] hostname [ port ] [ switches ]",
9201 " Opens a connection to the FTP server on the given host. The default",
9202 " TCP port is 21, but a different port number can be supplied if",
9203 " necessary. Optional switches are:",
9204 #endif /* CK_SSL */
9205 " ",
9206 " /ANONYMOUS",
9207 " Logs you in anonymously.",
9208 " /USER:text",
9209 " Supplies the given text as your username.",
9210 " /PASSWORD:text",
9211 " Supplies the given text as your password. If you include a username",
9212 " but omit this switch and the server requires a password, you are",
9213 " prompted for it.",
9214 " /ACCOUNT:text",
9215 " Supplies the given text as your account, if required by the server.",
9216 " /ACTIVE",
9217 " Forces an active (rather than passive) connection.",
9218 " /PASSIVE",
9219 " Forces a passive (rather than active) connection.",
9220 " /NOINIT",
9221 " Inhibits sending initial REST, STRU, and MODE commands, which are",
9222 " well-known standard commands, but to which some servers react badly.",
9223 " /NOLOGIN",
9224 " Inhibits autologin for this connection only.",
9225 ""
9226 };
9227 static char * fhs_opt[] = { /* OPTS, OPTIONS */
9228 "Syntax: FTP OPTIONS",
9229 " Asks the FTP server to list its current options. Advanced, new,",
9230 " not supported by most FTP servers.",
9231 ""
9232 };
9233 static char * fhs_put[] = { /* PUT, SEND */
9234 "Syntax: [ FTP ] PUT [ switches ] filespec [ as-name ]",
9235 " Like FTP MPUT, but only one filespec is allowed, and if it is followed",
9236 " by an additional field, this is interpreted as the name under which",
9237 " to send the file or files. See HELP FTP MPUT.",
9238 ""
9239 };
9240 static char * fhs_reput[] = { /* REPUT, RESEND */
9241 "Syntax: [ FTP ] REPUT [ switches ] filespec [ as-name ]",
9242 " Synonym for FTP PUT /RECOVER. Recovers an interrupted binary-mode",
9243 " upload from the point of failure if the FTP server supports recovery.",
9244 " Synonym: [ FTP ] RESEND. For details see HELP FTP MPUT.",
9245 ""
9246 };
9247 static char * fhs_pwd[] = { /* PWD */
9248 "Syntax: FTP PWD",
9249 " Asks the FTP server to reveal its current working directory.",
9250 " Synonyms: REMOTE PWD, RPWD.",
9251 ""
9252 };
9253 static char * fhs_quo[] = { /* QUOTE */
9254 "Syntax: FTP QUOTE text",
9255 " Sends an FTP protocol command to the FTP server. Use this command",
9256 " for sending commands that Kermit might not support.",
9257 ""
9258 };
9259 static char * fhs_rge[] = { /* REGET */
9260 "Syntax: FTP REGET",
9261 " Synonym for FTP GET /RECOVER.",
9262 ""
9263 };
9264 static char * fhs_ren[] = { /* RENAME */
9265 "Syntax: FTP RENAME name1 name1",
9266 " Asks the FTP server to change the name of the file whose name is name1",
9267 " and which resides in the FTP server's file system, to name2. Works",
9268 " only for single files; wildcards are not accepted.",
9269 ""
9270 };
9271 static char * fhs_res[] = { /* RESET */
9272 "Syntax: FTP RESET",
9273 " Asks the server to log out your session, terminating your access",
9274 " rights, without closing the connection.",
9275 ""
9276 };
9277 static char * fhs_rmd[] = { /* RMDIR */
9278 "Syntax: FTP RMDIR directory",
9279 " Asks the FTP server to remove the directory whose name is given.",
9280 " This usually requires the directory to be empty. Synonyms: REMOTE",
9281 " RMDIR, RRMDIR.",
9282 ""
9283 };
9284 static char * fhs_sit[] = { /* SITE */
9285 "Syntax: FTP SITE text",
9286 " Sends a site-specific command to the FTP server.",
9287 ""
9288 };
9289 static char * fhs_siz[] = { /* SIZE */
9290 "Syntax: FTP SIZE filename",
9291 " Asks the FTP server to send a numeric string representing the size",
9292 " of the given file.",
9293 ""
9294 };
9295 static char * fhs_sta[] = { /* STATUS */
9296 "Syntax: FTP STATUS [ filename ]",
9297 " Asks the FTP server to report its status. If a filename is given,",
9298 " the FTP server should report details about the file.",
9299 ""
9300 };
9301 static char * fhs_sys[] = { /* SYSTEM */
9302 "Syntax: FTP SYSTEM",
9303 " Asks the FTP server to report its operating system type.",
9304 ""
9305 };
9306 static char * fhs_typ[] = { /* TYPE */
9307 "Syntax: FTP TYPE { TEXT, BINARY, TENEX }",
9308 " Puts the client and server in the indicated transfer mode.",
9309 " ASCII is a synonym for TEXT. TENEX is used only for uploading 8-bit",
9310 " binary files to a 36-bit platforms such as TENEX or TOPS-20 and/or",
9311 " downloading files from TENEX or TOPS-20 that have been uploaded in",
9312 " TENEX mode.",
9313 ""
9314 };
9315 static char * fhs_uma[] = { /* UMASK */
9316 "Syntax: FTP UMASK number",
9317 " Asks the FTP server to set its file creation mode mask. Applies",
9318 " only (or mainly) to UNIX-based FTP servers.",
9319 ""
9320 };
9321 static char * fhs_chk[] = { /* CHECK */
9322 "Syntax: FTP CHECK remote-filespec",
9323 " Asks the FTP server if the given file or files exist. If the",
9324 " remote-filespec contains wildcards, this command fails if no server",
9325 " files match, and succeeds if at least one file matches. If the",
9326 " remote-filespec does not contain wildcards, this command succeeds if",
9327 " the given file exists and fails if it does not.",
9328 ""
9329 };
9330 static char * fhs_ena[] = { /* ENABLE */
9331 "Syntax: FTP ENABLE { AUTH, FEAT, MDTM, MLST, SIZE }",
9332 " Enables the use of the given FTP protocol command in case it has been",
9333 " disabled (but this is no guarantee that the FTP server understands it)."
9334 ,
9335 " Use SHOW FTP to see which of these commands is enabled and disabled.",
9336 " Also see FTP DISABLE.",
9337 ""
9338 };
9339 static char * fhs_dis[] = { /* DISABLE */
9340 "Syntax: FTP DISABLE { AUTH, FEAT, MDTM, MLST, SIZE }",
9341 " Disables the use of the given FTP protocol command.",
9342 " Also see FTP ENABLE.",
9343 ""
9344 };
9345
9346 #endif /* NOHELP */
9347
9348 int
doftphlp()9349 doftphlp() {
9350 int cx;
9351 if ((cx = cmkey(ftpcmdtab,nftpcmd,"","",xxstring)) < 0)
9352 if (cx != -3)
9353 return(cx);
9354 if ((x = cmcfm()) < 0)
9355 return(x);
9356
9357 #ifdef NOHELP
9358 printf("Sorry, no help available\n");
9359 #else
9360 switch (cx) {
9361 case -3:
9362 return(hmsga(fhs_ftp));
9363 case FTP_ACC: /* ACCOUNT */
9364 return(hmsga(fhs_acc));
9365 case FTP_APP: /* APPEND */
9366 return(hmsga(fhs_app));
9367 case FTP_CLS: /* BYE, CLOSE */
9368 return(hmsga(fhs_cls));
9369 case FTP_CWD: /* CD, CWD */
9370 return(hmsga(fhs_cwd));
9371 case FTP_GUP: /* CDUP, UP */
9372 return(hmsga(fhs_gup));
9373 case FTP_CHM: /* CHMOD */
9374 return(hmsga(fhs_chm));
9375 case FTP_MDE: /* DELETE, MDELETE */
9376 return(hmsga(fhs_mde));
9377 case FTP_DIR: /* DIRECTORY */
9378 return(hmsga(fhs_dir));
9379 case FTP_VDI: /* VDIRECTORY */
9380 return(hmsga(fhs_vdi));
9381 case FTP_FEA: /* FEATURES */
9382 return(hmsga(fhs_fea));
9383 case FTP_GET: /* GET */
9384 return(hmsga(fhs_get));
9385 case FTP_HLP: /* HELP */
9386 return(hmsga(fhs_hlp));
9387 case FTP_IDL: /* IDLE */
9388 return(hmsga(fhs_idl));
9389 case FTP_USR: /* USER, LOGIN */
9390 return(hmsga(fhs_usr));
9391 case FTP_MGE: /* MGET */
9392 return(hmsga(fhs_mge));
9393 case FTP_MKD: /* MKDIR */
9394 return(hmsga(fhs_mkd));
9395 case FTP_MOD: /* MODTIME */
9396 return(hmsga(fhs_mod));
9397 case FTP_MPU: /* MPUT */
9398 return(hmsga(fhs_mpu));
9399 case FTP_OPN: /* OPEN */
9400 return(hmsga(fhs_opn));
9401 case FTP_OPT: /* OPTS, OPTIONS */
9402 return(hmsga(fhs_opt));
9403 case FTP_PUT: /* PUT, SEND */
9404 return(hmsga(fhs_put));
9405 case FTP_REP: /* REPUT, RESEND */
9406 return(hmsga(fhs_reput));
9407 case FTP_PWD: /* PWD */
9408 return(hmsga(fhs_pwd));
9409 case FTP_QUO: /* QUOTE */
9410 return(hmsga(fhs_quo));
9411 case FTP_RGE: /* REGET */
9412 return(hmsga(fhs_rge));
9413 case FTP_REN: /* RENAME */
9414 return(hmsga(fhs_ren));
9415 case FTP_RES: /* RESET */
9416 return(hmsga(fhs_res));
9417 case FTP_RMD: /* RMDIR */
9418 return(hmsga(fhs_rmd));
9419 case FTP_SIT: /* SITE */
9420 return(hmsga(fhs_sit));
9421 case FTP_SIZ: /* SIZE */
9422 return(hmsga(fhs_siz));
9423 case FTP_STA: /* STATUS */
9424 return(hmsga(fhs_sta));
9425 case FTP_SYS: /* SYSTEM */
9426 return(hmsga(fhs_sys));
9427 case FTP_TYP: /* TYPE */
9428 return(hmsga(fhs_typ));
9429 case FTP_UMA: /* UMASK */
9430 return(hmsga(fhs_uma));
9431 case FTP_CHK: /* CHECK */
9432 return(hmsga(fhs_chk));
9433 case FTP_ENA:
9434 return(hmsga(fhs_ena));
9435 case FTP_DIS:
9436 return(hmsga(fhs_dis));
9437 default:
9438 printf("Sorry, help available for this command.\n");
9439 break;
9440 }
9441 #endif /* NOHELP */
9442 return(success = 0);
9443 }
9444
9445 int
dosetftphlp()9446 dosetftphlp() {
9447 int cx;
9448 if ((cx = cmkey(ftpset,nftpset,"","",xxstring)) < 0)
9449 if (cx != -3)
9450 return(cx);
9451 if (cx != -3)
9452 ckstrncpy(tmpbuf,atmbuf,TMPBUFSIZ);
9453 if ((x = cmcfm()) < 0)
9454 return(x);
9455
9456 #ifdef NOHELP
9457 printf("Sorry, no help available\n");
9458 #else
9459 switch (cx) {
9460 case -3:
9461 printf("\nSyntax: SET FTP parameter value\n");
9462 printf(" Type \"help set ftp ?\" for a list of parameters.\n");
9463 printf(" Type \"help set ftp xxx\" for information about setting\n");
9464 printf(" parameter xxx. Type \"show ftp\" for current values.\n\n");
9465 return(0);
9466
9467 case FTS_BUG:
9468 printf("\nSyntax: SET FTP BUG <name> {ON, OFF}\n");
9469 printf(
9470 " Activates a workaround for the named bug in the FTP server.\n");
9471 printf(" Type SET FTP BUG ? for a list of names.\n");
9472 printf(" For each bug, the default is OFF\n\n");
9473 return(0);
9474
9475 #ifdef FTP_SECURITY
9476 case FTS_ATP: /* "authtype" */
9477 printf("\nSyntax: SET FTP AUTHTYPE list\n");
9478 printf(" Specifies an ordered list of authentication methods to be\n"
9479 );
9480 printf(" when FTP AUTOAUTHENTICATION is ON. The default list is:\n");
9481 printf(" GSSAPI-KRB5, SRP, KERBEROS_V4, TLS, SSL.\n\n");
9482 return(0);
9483
9484 case FTS_AUT: /* "autoauthentication" */
9485 printf("\nSyntax:SET FTP AUTOAUTHENTICATION { ON, OFF }\n");
9486 printf(" Tells whether authentication should be negotiated by the\n");
9487 printf(" FTP OPEN command. Default is ON.\n\n");
9488 break;
9489
9490 case FTS_CRY: /* "autoencryption" */
9491 printf("\nSET FTP AUTOENCRYPTION { ON, OFF }\n");
9492 printf(" Tells whether encryption (privacy) should be negotiated\n");
9493 printf(" by the FTP OPEN command. Default is ON.\n\n");
9494 break;
9495 #endif /* FTP_SECURITY */
9496
9497 case FTS_LOG: /* "autologin" */
9498 printf("\nSET FTP AUTOLOGIN { ON, OFF }\n");
9499 printf(" Tells Kermit whether to try to log you in automatically\n");
9500 printf(" as part of the connection process.\n\n");
9501 break;
9502
9503 case FTS_DIS:
9504 printf("\nSET FTP DISPLAY { BRIEF, FULLSCREEN, CRT, ... }\n");
9505 printf(" Chooses the file-transfer display style for FTP.\n");
9506 printf(" Like SET TRANSFER DISPLAY but applies only to FTP.\n\n");
9507 break;
9508
9509 #ifndef NOCSETS
9510 case FTS_XLA: /* "character-set-translation" */
9511 printf("\nSET FTP CHARACTER-SET-TRANSLATION { ON, OFF }\n");
9512 printf(" Whether to translate character sets when transferring\n");
9513 printf(" text files with FTP. OFF by default.\n\n");
9514 break;
9515
9516 #endif /* NOCSETS */
9517 case FTS_FNC: /* "collision" */
9518 printf("\n");
9519 printf(
9520 "Syntax: SET FTP COLLISION { BACKUP,RENAME,UPDATE,DISCARD,APPEND,OVERWRITE }\n"
9521 );
9522 printf(" Tells what do when an incoming file has the same name as\n");
9523 printf(" an existing file when downloading with FTP.\n\n");
9524 break;
9525
9526 #ifdef FTP_SECURITY
9527 case FTS_CPL: /* "command-protection-level" */
9528 printf("\n");
9529 printf(
9530 "Syntax: SET FTP COMMAND-PROTECTION-LEVEL { CLEAR,CONFIDENTIAL,PRIVATE,SAFE }"
9531 );
9532 printf("\n");
9533 printf(
9534 " Tells what level of protection is applied to the FTP command channel.\n\n");
9535 break;
9536 case FTS_CFW: /* "credential-forwarding" */
9537 printf("\nSyntax: SET FTP CREDENTIAL-FORWARDING { ON, OFF }\n");
9538 printf(" Tells whether end-user credentials are to be forwarded\n");
9539 printf(" to the server if supported by the authentication method\n");
9540 printf(" (GSSAPI-KRB5 only).\n\n");
9541 break;
9542 case FTS_DPL: /* "data-protection-level" */
9543 printf("\n");
9544 printf(
9545 "Syntax: SET FTP DATA-PROTECTION-LEVEL { CLEAR,CONFIDENTIAL,PRIVATE,SAFE }"
9546 );
9547 printf("\n");
9548 printf(
9549 " Tells what level of protection is applied to the FTP data channel.\n\n");
9550 break;
9551 #endif /* FTP_SECURITY */
9552
9553 case FTS_DBG: /* "debug" */
9554 printf("\nSyntax: SET FTP DEBUG { ON, OFF }\n");
9555 printf(" Whether to print FTP protocol messages.\n\n");
9556 return(0);
9557
9558 case FTS_ERR: /* "error-action" */
9559 printf("\nSyntax: SET FTP ERROR-ACTION { QUIT, PROCEED }\n");
9560 printf(" What to do when an error occurs when transferring a group\n")
9561 ;
9562 printf(" of files: quit and fail, or proceed to the next file.\n\n");
9563 return(0);
9564
9565 case FTS_CNV: /* "filenames" */
9566 printf("\nSyntax: SET FTP FILENAMES { AUTO, CONVERTED, LITERAL }\n");
9567 printf(" What to do with filenames: convert them, take and use them\n"
9568 );
9569 printf(" literally; or choose what to do automatically based on the\n"
9570 );
9571 printf(" OS type of the server. The default is AUTO.\n\n");
9572 return(0);
9573
9574 case FTS_PSV: /* "passive-mode" */
9575 printf("\nSyntax: SET FTP PASSIVE-MODE { ON, OFF }\n");
9576 printf(" Whether to use passive mode, which helps to get through\n");
9577 printf(" firewalls. ON by default.\n\n");
9578 return(0);
9579
9580 case FTS_PRM: /* "permissions" */
9581 printf("\nSyntax: SET FTP PERMISSIONS { AUTO, ON, OFF }\n");
9582 printf(" Whether to try to send file permissions when uploading.\n");
9583 printf(" OFF by default. AUTO means only if client and server\n");
9584 printf(" have the same OS type.\n\n");
9585 return(0);
9586
9587 case FTS_TST: /* "progress-messages" */
9588 printf("\nSyntax: SET FTP PROGRESS-MESSAGES { ON, OFF }\n");
9589 printf(" Whether Kermit should print locally-generated feedback\n");
9590 printf(" messages for each non-file-transfer command.");
9591 printf(" ON by default.\n\n");
9592 return(0);
9593
9594 case FTS_SPC: /* "send-port-commands" */
9595 printf("\nSyntax: SET FTP SEND-PORT-COMMANDS { ON, OFF }\n");
9596 printf(" Whether Kermit should send a new PORT command for each");
9597 printf(" task.\n\n");
9598 return(0);
9599
9600 #ifndef NOCSETS
9601 case FTS_CSR: /* "server-character-set" */
9602 printf("\nSyntax: SET FTP SERVER-CHARACTER-SET name\n");
9603 printf(" The name of the character set used for text files on the\n");
9604 printf(" server. Enter a name of '?' for a menu.\n\n");
9605 return(0);
9606 #endif /* NOCSETS */
9607
9608 case FTS_STO: /* "server-time-offset */
9609 printf(
9610 "\nSyntax: SET FTP SERVER-TIME-OFFSET +hh[:mm[:ss]] or -hh[:mm[:ss]]\n");
9611 printf(
9612 " Specifies an offset to apply to the server's file timestamps.\n");
9613 printf(
9614 " Use this to correct for misconfigured server time or timezone.\n");
9615 printf(
9616 " Format: must begin with + or - sign. Hours must be given; minutes\n");
9617 printf(
9618 " and seconds are optional: +4 = +4:00 = +4:00:00 (add 4 hours).\n\n");
9619 return(0);
9620
9621 case FTS_TYP: /* "type" */
9622 printf("\nSyntax: SET FTP TYPE { TEXT, BINARY, TENEX }\n");
9623 printf(" Establishes the default transfer mode.\n");
9624 printf(" TENEX is used for uploading 8-bit binary files to 36-bit\n");
9625 printf(" platforms such as TENEX and TOPS-20 and for downloading\n");
9626 printf(" them again. ASCII is a synonym for TEXT. Normally each\n");
9627 printf(" file's type is determined automatically from its contents\n"
9628 );
9629 printf(" or its name; SET FTP TYPE does not prevent that, it only\n");
9630 printf(" tells which mode to use when the type can't be determined\n"
9631 );
9632 printf(" automatically. To completely disable automatic transfer-\n"
9633 );
9634 printf(" mode switching and force either text or binary mode, give\n"
9635 );
9636 printf(" the top-level command ASCII or BINARY, as in traditional\n");
9637 printf(" FTP clients.\n\n");
9638 return(0);
9639
9640 #ifdef FTP_TIMEOUT
9641 case FTS_TMO:
9642 printf("\nSyntax: SET FTP TIMEOUT number-of-seconds\n");
9643 printf(" Establishes a timeout for FTP transfers.\n");
9644 printf(" The timeout applies per network read or write on the data\n");
9645 printf(" connection, not to the whole transfer. By default the\n");
9646 printf(" timeout value is 0, meaning no timeout. Use a positive\n");
9647 printf(" number to escape gracefully from hung data connections or\n");
9648 printf(" directory listings.\n\n");
9649 return(0);
9650 #endif /* FTP_TIMEOUT */
9651
9652 #ifdef PATTERNS
9653 case FTS_GFT:
9654 printf("\nSyntax: SET FTP GET-FILETYPE-SWITCHING { ON, OFF }\n");
9655 printf(" Tells whether GET and MGET should automatically switch\n");
9656 printf(" the appropriate file type, TEXT, BINARY, or TENEX, by\n");
9657 printf(" matching the name of each incoming file with its list of\n");
9658 printf(" FILE TEXT-PATTERNS and FILE BINARY-PATTERNS. ON by\n");
9659 printf(" default. SHOW PATTERNS displays the current pattern\n");
9660 printf(" list. HELP SET FILE to see how to change it.\n");
9661 break;
9662 #endif /* PATTERNS */
9663
9664 case FTS_USN: /* "unique-server-names" */
9665 printf("\nSyntax: SET FTP UNIQUE-SERVER-NAMES { ON, OFF }\n");
9666 printf(" Tells whether to ask the server to create unique names\n");
9667 printf(" for any uploaded file that has the same name as an\n");
9668 printf(" existing file. Default is OFF.\n\n");
9669 return(0);
9670
9671 case FTS_VBM: /* "verbose-mode" */
9672 printf("\nSyntax: SET FTP VERBOSE-MODE { ON, OFF }\n");
9673 printf(" Whether to display all responses from the FTP server.\n");
9674 printf(" OFF by default.\n\n");
9675 return(0);
9676
9677 case FTS_DAT:
9678 printf("\nSyntax: SET FTP DATES { ON, OFF }\n");
9679 printf(" Whether to set date of incoming files from the file date\n");
9680 printf(" on the server. ON by default. Note: there is no way to\n")
9681 ;
9682 printf(" set the date on files uploaded to the server. Also note\n");
9683 printf(" that not all servers support this feature.\n\n");
9684 return(0);
9685
9686 case FTS_APW:
9687 printf("\nSyntax: SET FTP ANONYMOUS-PASSWORD [ text ]\n");
9688 printf(" Password to supply automatically on anonymous FTP\n");
9689 printf(" connections instead of the default user@host.\n");
9690 printf(" Omit optional text to restore default.\n\n");
9691 return(0);
9692
9693 default:
9694 printf("Sorry, help not available for \"set ftp %s\"\n",tmpbuf);
9695 }
9696 #endif /* NOHELP */
9697 return(0);
9698 }
9699
9700 #ifndef L_SET
9701 #define L_SET 0
9702 #endif /* L_SET */
9703 #ifndef L_INCR
9704 #define L_INCR 1
9705 #endif /* L_INCR */
9706
9707 #ifdef FTP_SRP
9708 char srp_user[BUFSIZ]; /* where is BUFSIZ defined? */
9709 char *srp_pass;
9710 char *srp_acct;
9711 #endif /* FTP_SRP */
9712
9713 static int kerror; /* Needed for all auth types */
9714
9715 static struct sockaddr_in hisctladdr;
9716 static struct sockaddr_in hisdataaddr;
9717 static struct sockaddr_in data_addr;
9718 static int data = -1;
9719 static int ptflag = 0;
9720 static struct sockaddr_in myctladdr;
9721
9722 #ifdef COMMENT
9723 #ifndef OS2
9724 UID_T getuid();
9725 #endif /* OS2 */
9726 #endif /* COMMENT */
9727
9728
9729 static int cpend = 0; /* No pending replies */
9730
9731 #ifdef CK_SSL
9732 extern SSL *ssl_ftp_con;
9733 extern SSL_CTX *ssl_ftp_ctx;
9734 extern SSL *ssl_ftp_data_con;
9735 extern int ssl_ftp_active_flag;
9736 extern int ssl_ftp_data_active_flag;
9737 #endif /* CK_SSL */
9738
9739 /* f t p c m d -- Send a command to the FTP server */
9740 /*
9741 Call with:
9742 char * cmd: The command to send.
9743 char * arg: The argument (e.g. a filename).
9744 int lcs: The local character set index.
9745 int rcs: The remote (server) character set index.
9746 int vbm: Verbose mode:
9747 0 = force verbosity off
9748 >0 = force verbosity on
9749
9750 If arg is given (not NULL or empty) and lcs != rcs and both are > -1,
9751 and neither lcs or rcs is UCS-2, the arg is translated from the local
9752 character set to the remote one before sending the result to the server.
9753
9754 Returns:
9755 0 on failure with ftpcode = -1
9756 >= 0 on success (getreply() result) with ftpcode = 0.
9757 */
9758 static char xcmdbuf[RFNBUFSIZ];
9759
9760 static int
ftpcmd(cmd,arg,lcs,rcs,vbm)9761 ftpcmd(cmd,arg,lcs,rcs,vbm) char * cmd, * arg; int lcs, rcs, vbm; {
9762 char * s = NULL;
9763 int r = 0, x = 0, fc = 0, len = 0, cmdlen = 0, q = -1;
9764 sig_t oldintr;
9765
9766 if (ftp_deb) /* DEBUG */
9767 vbm = 1;
9768 else if (quiet || dpyactive) /* QUIET or File Transfer Active */
9769 vbm = 0;
9770 else if (vbm < 0) /* VERBOSE */
9771 vbm = ftp_vbm;
9772
9773 cancelfile = 0;
9774 if (!cmd) cmd = "";
9775 if (!arg) arg = "";
9776 cmdlen = (int)strlen(cmd);
9777 len = cmdlen + (int)strlen(arg) + 1;
9778
9779 if (ftp_deb /* && !dpyactive */ ) {
9780 #ifdef FTP_PROXY
9781 if (ftp_prx) printf("%s ", ftp_host);
9782 #endif /* FTP_PROXY */
9783 printf("---> ");
9784 if (!anonymous && strcmp("PASS",cmd) == 0)
9785 printf("PASS XXXX");
9786 else
9787 printf("%s %s",cmd,arg);
9788 printf("\n");
9789 }
9790 /* bzero(xcmdbuf,RFNBUFSIZ); */
9791 ckmakmsg(xcmdbuf,RFNBUFSIZ, cmd, *arg ? " " : "", arg, NULL);
9792
9793 #ifdef DEBUG
9794 if (deblog) {
9795 debug(F110,"ftpcmd cmd",cmd,0);
9796 debug(F110,"ftpcmd arg",arg,0);
9797 debug(F101,"ftpcmd lcs","",lcs);
9798 debug(F101,"ftpcmd rcs","",rcs);
9799 }
9800 #endif /* DEBUG */
9801
9802 if (csocket == -1) {
9803 perror("No control connection for command");
9804 ftpcode = -1;
9805 return(0);
9806 }
9807 havesigint = 0;
9808 oldintr = signal(SIGINT, cmdcancel);
9809
9810 #ifndef NOCSETS
9811 if (*arg && /* If an arg was given */
9812 lcs > -1 && /* and a local charset */
9813 rcs > -1 && /* and a remote charset */
9814 lcs != rcs && /* and the two are not the same */
9815 lcs != FC_UCS2 && /* and neither one is UCS-2 */
9816 rcs != FC_UCS2 /* ... */
9817 ) {
9818 initxlate(lcs,rcs); /* Translate arg from lcs to rcs */
9819 xgnbp = arg; /* Global pointer to input string */
9820 rfnptr = rfnbuf; /* Global pointer to output buffer */
9821
9822 while (1) {
9823 if ((c0 = xgnbyte(FC_UCS2,lcs,strgetc)) < 0) break;
9824 if (xpnbyte(c0,TC_UCS2,rcs,strputc) < 0) break;
9825 }
9826 /*
9827 We have to copy here instead of translating directly into
9828 xcmdbuf[] so strputc() can check length. Alternatively we could
9829 write yet another xpnbyte() output function.
9830 */
9831 if ((int)strlen(rfnbuf) > (RFNBUFSIZ - (cmdlen+1))) {
9832 printf("?FTP command too long: %s + arg\n",cmd);
9833 ftpcode = -1;
9834 return(0);
9835 }
9836 x = ckstrncpy(&xcmdbuf[cmdlen+1], rfnbuf, RFNBUFSIZ - (cmdlen+1));
9837 }
9838 #endif /* NOCSETS */
9839
9840 s = xcmdbuf; /* Command to send to server */
9841
9842 #ifdef DEBUG
9843 if (deblog) { /* Log it */
9844 if (!anonymous && !ckstrcmp(s,"PASS ",5,0)) {
9845 /* But don't log passwords */
9846 debug(F110,"FTP SENT ","PASS XXXX",0);
9847 } else {
9848 debug(F110,"FTP SENT ",s,0);
9849 }
9850 }
9851 #endif /* DEBUG */
9852
9853 #ifdef CK_ENCRYPTION
9854 again:
9855 #endif /* CK_ENCRYPTION */
9856 if (scommand(s) == 0) { /* Send it. */
9857 signal(SIGINT, oldintr);
9858 return(0);
9859 }
9860 cpend = 1;
9861 x = !strcmp(cmd,"QUIT"); /* Is it the QUIT command? */
9862 if (x) /* In case we're interrupted */
9863 connected = 0; /* while waiting for the reply... */
9864
9865 fc = 0; /* Function code for getreply() */
9866 if (!strncmp(cmd,"AUTH ",5) /* Must parse AUTH reply */
9867 #ifdef FTPHOST
9868 && strncmp(cmd, "HOST ",5)
9869 #endif /* FTPHOST */
9870 ) {
9871 fc = GRF_AUTH;
9872 } else if (!ckstrcmp(cmd,"FEAT",-1,0)) { /* Must parse FEAT reply */
9873 fc = GRF_FEAT; /* But FEAT not widely understood */
9874 if (!ftp_deb) /* So suppress error messages */
9875 vbm = 9;
9876 }
9877 r = getreply(x, /* Expect connection to close */
9878 lcs,rcs, /* Charsets */
9879 vbm, /* Verbosity */
9880 fc /* Function code */
9881 );
9882 if (q > -1)
9883 quiet = q;
9884
9885 #ifdef CK_ENCRYPTION
9886 if (ftpcode == 533 && ftp_cpl == FPL_PRV) {
9887 fprintf(stderr,
9888 "ENC command not supported at server; retrying under MIC...\n");
9889 ftp_cpl = FPL_SAF;
9890 goto again;
9891 }
9892 #endif /* CK_ENCRYPTION */
9893 #ifdef COMMENT
9894 if (cancelfile && oldintr != SIG_IGN)
9895 (*oldintr)(SIGINT);
9896 #endif /* COMMENT */
9897 signal(SIGINT, oldintr);
9898 return(r);
9899 }
9900
9901 static VOID
lostpeer()9902 lostpeer() {
9903 debug(F100,"lostpeer","",0);
9904 if (connected) {
9905 if (csocket != -1) {
9906 #ifdef CK_SSL
9907 if (ssl_ftp_active_flag) {
9908 SSL_shutdown(ssl_ftp_con);
9909 SSL_free(ssl_ftp_con);
9910 ssl_ftp_proxy = 0;
9911 ssl_ftp_active_flag = 0;
9912 ssl_ftp_con = NULL;
9913 }
9914 #endif /* CK_SSL */
9915 #ifdef TCPIPLIB
9916 socket_close(csocket);
9917 #else /* TCPIPLIB */
9918 #ifdef USE_SHUTDOWN
9919 shutdown(csocket, 1+1);
9920 #endif /* USE_SHUTDOWN */
9921 close(csocket);
9922 #endif /* TCPIPLIB */
9923 csocket = -1;
9924 }
9925 if (data != -1) {
9926 #ifdef CK_SSL
9927 if (ssl_ftp_data_active_flag) {
9928 SSL_shutdown(ssl_ftp_data_con);
9929 SSL_free(ssl_ftp_data_con);
9930 ssl_ftp_data_active_flag = 0;
9931 ssl_ftp_data_con = NULL;
9932 }
9933 #endif /* CK_SSL */
9934 #ifdef TCPIPLIB
9935 socket_close(data);
9936 #else /* TCPIPLIB */
9937 #ifdef USE_SHUTDOWN
9938 shutdown(data, 1+1);
9939 #endif /* USE_SHUTDOWN */
9940 close(data);
9941 #endif /* TCPIPLIB */
9942 data = -1;
9943 globaldin = -1;
9944 }
9945 connected = 0;
9946 anonymous = 0;
9947 loggedin = 0;
9948 auth_type = NULL;
9949 ftp_cpl = ftp_dpl = FPL_CLR;
9950 #ifdef CKLOGDIAL
9951 ftplogend();
9952 #endif /* CKLOGDIAL */
9953
9954 #ifdef LOCUS
9955 if (autolocus) /* Auotomatic locus switching... */
9956 setlocus(1,1); /* Switch locus to local. */
9957 #endif /* LOCUS */
9958 #ifdef OS2
9959 DialerSend(OPT_KERMIT_HANGUP, 0);
9960 #endif /* OS2 */
9961 }
9962 #ifdef FTP_PROXY
9963 pswitch(1);
9964 if (connected) {
9965 if (csocket != -1) {
9966 #ifdef TCPIPLIB
9967 socket_close(csocket);
9968 #else /* TCPIPLIB */
9969 #ifdef USE_SHUTDOWN
9970 shutdown(csocket, 1+1);
9971 #endif /* USE_SHUTDOWN */
9972 close(csocket);
9973 #endif /* TCPIPLIB */
9974 csocket = -1;
9975 }
9976 connected = 0;
9977 anonymous = 0;
9978 loggedin = 0;
9979 auth_type = NULL;
9980 ftp_cpl = ftp_dpl = FPL_CLR;
9981 }
9982 proxflag = 0;
9983 pswitch(0);
9984 #endif /* FTP_PROXY */
9985 }
9986
9987 int
ftpisopen()9988 ftpisopen() {
9989 return(connected);
9990 }
9991
9992 static int
ftpclose()9993 ftpclose() {
9994 extern int quitting;
9995 if (!connected)
9996 return(0);
9997 ftp_xfermode = xfermode;
9998 if (!ftp_vbm && !quiet)
9999 printlines = 1;
10000 ftpcmd("QUIT",NULL,0,0,ftp_vbm);
10001 if (csocket) {
10002 #ifdef CK_SSL
10003 if (ssl_ftp_active_flag) {
10004 SSL_shutdown(ssl_ftp_con);
10005 SSL_free(ssl_ftp_con);
10006 ssl_ftp_proxy = 0;
10007 ssl_ftp_active_flag = 0;
10008 ssl_ftp_con = NULL;
10009 }
10010 #endif /* CK_SSL */
10011 #ifdef TCPIPLIB
10012 socket_close(csocket);
10013 #else /* TCPIPLIB */
10014 #ifdef USE_SHUTDOWN
10015 shutdown(csocket, 1+1);
10016 #endif /* USE_SHUTDOWN */
10017 close(csocket);
10018 #endif /* TCPIPLIB */
10019 }
10020 csocket = -1;
10021 connected = 0;
10022 anonymous = 0;
10023 loggedin = 0;
10024 mdtmok = 1;
10025 sizeok = 1;
10026 featok = 1;
10027 stouarg = 1;
10028 typesent = 0;
10029 data = -1;
10030 globaldin = -1;
10031 #ifdef FTP_PROXY
10032 if (!proxy)
10033 macnum = 0;
10034 #endif /* FTP_PROXY */
10035 auth_type = NULL;
10036 ftp_dpl = FPL_CLR;
10037 #ifdef CKLOGDIAL
10038 ftplogend();
10039 #endif /* CKLOGDIAL */
10040 #ifdef LOCUS
10041 /* Unprefixed file management commands are executed locally */
10042 if (autolocus && !ftp_cmdlin && !quitting) {
10043 setlocus(1,1);
10044 }
10045 #endif /* LOCUS */
10046 #ifdef OS2
10047 DialerSend(OPT_KERMIT_HANGUP, 0);
10048 #endif /* OS2 */
10049 return(0);
10050 }
10051
10052 int
ftpopen(remote,service,use_tls)10053 ftpopen(remote, service, use_tls) char * remote, * service; int use_tls; {
10054 char * host;
10055
10056 if (connected) {
10057 printf("?Already connected to %s, use FTP CLOSE first.\n", ftp_host);
10058 ftpcode = -1;
10059 return(0);
10060 }
10061 #ifdef FTPHOST
10062 hostcmd = 0;
10063 #endif /* FTPHOST */
10064 alike = 0;
10065 ftp_srvtyp[0] = NUL;
10066 if (!service) service = "";
10067 if (!*service) service = use_tls ? "ftps" : "ftp";
10068
10069 if (!isdigit(service[0])) {
10070 struct servent *destsp;
10071 destsp = getservbyname(service, "tcp");
10072 if (!destsp) {
10073 if (!ckstrcmp(service,"ftp",-1,0)) {
10074 ftp_port = 21;
10075 } else if (!ckstrcmp(service,"ftps",-1,0)) {
10076 ftp_port = 990;
10077 } else {
10078 printf("?Bad port name - \"%s\"\n", service);
10079 ftpcode = -1;
10080 return(0);
10081 }
10082 } else {
10083 ftp_port = destsp->s_port;
10084 ftp_port = ntohs((unsigned short)ftp_port); /* SMS 2007/02/15 */
10085 }
10086 } else
10087 ftp_port = atoi(service);
10088 if (ftp_port <= 0) {
10089 printf("?Bad port name - \"%s\"\n", service);
10090 ftpcode = -1;
10091 return(0);
10092 }
10093 host = ftp_hookup(remote, ftp_port, use_tls);
10094 if (host) {
10095 ckstrncpy(ftp_user_host,remote,MAX_DNS_NAMELEN);
10096 connected = 1; /* Set FTP defaults */
10097 ftp_cpl = ftp_dpl = FPL_CLR;
10098 curtype = FTT_ASC; /* Server uses ASCII mode */
10099 form = FORM_N;
10100 mode = MODE_S;
10101 stru = STRU_F;
10102 strcpy(bytename, "8");
10103 bytesize = 8;
10104
10105 #ifdef FTP_SECURITY
10106 if (ftp_aut) {
10107 if (ftp_auth()) {
10108 if (ftp_cry
10109 #ifdef OS2
10110 && ck_crypt_is_installed()
10111 #endif /* OS2 */
10112 ) {
10113 if (!quiet)
10114 printf("FTP Command channel is Private (encrypted)\n");
10115 ftp_cpl = FPL_PRV;
10116 if (setpbsz(DEFAULT_PBSZ) < 0) {
10117 /* a failure here is most likely caused by a mixup */
10118 /* in the session key used by client and server */
10119 printf("?Protection buffer size negotiation failed\n");
10120 return(0);
10121 }
10122 if (ftpcmd("PROT P",NULL,0,0,ftp_vbm) == REPLY_COMPLETE) {
10123 if (!quiet)
10124 printf("FTP Data channel is Private (encrypted)\n");
10125 ftp_dpl = FPL_PRV;
10126 } else
10127 printf("?Unable to enable encryption on data channel\n");
10128 } else {
10129 ftp_cpl = FPL_SAF;
10130 }
10131 }
10132 if (!connected)
10133 goto fail;
10134 }
10135 #endif /* FTP_SECURITY */
10136 if (ftp_log) /* ^^^ */
10137 ftp_login(remote);
10138
10139 if (!connected)
10140 goto fail;
10141
10142 ftp_xfermode = xfermode;
10143
10144 #ifdef CKLOGDIAL
10145 dologftp();
10146 #endif /* CKLOGDIAL */
10147 #ifdef OS2
10148 DialerSend(OPT_KERMIT_CONNECT, 0);
10149 #endif /* OS2 */
10150 passivemode = ftp_psv;
10151 sendport = ftp_spc;
10152 mdtmok = 1;
10153 sizeok = 1;
10154 stouarg = 1;
10155 typesent = 0;
10156
10157 if (ucbuf == NULL) {
10158 actualbuf = DEFAULT_PBSZ;
10159 while (actualbuf && (ucbuf = (CHAR *)malloc(actualbuf)) == NULL)
10160 actualbuf >>= 2;
10161 }
10162 if (!maxbuf)
10163 ucbufsiz = actualbuf - FUDGE_FACTOR;
10164 debug(F101,"ftpopen ucbufsiz","",ucbufsiz);
10165 return(1);
10166 }
10167 fail:
10168 printf("?Can't FTP connect to %s:%s\n",remote,service);
10169 ftpcode = -1;
10170 return(0);
10171 }
10172
10173 #ifdef CK_SSL
10174 int
ssl_auth()10175 ssl_auth() {
10176 int i;
10177 char* p;
10178 CONST SSL_METHOD *client_method;
10179
10180 if (ssl_debug_flag) {
10181 fprintf(stderr,"SSL DEBUG ACTIVE\n");
10182 fflush(stderr);
10183 /* for the moment I want the output on screen */
10184 }
10185 if (ssl_ftp_data_con != NULL) {
10186 SSL_free(ssl_ftp_data_con);
10187 ssl_ftp_data_con = NULL;
10188 }
10189 if (ssl_ftp_con != NULL) {
10190 SSL_free(ssl_ftp_con);
10191 ssl_ftp_con=NULL;
10192 }
10193 if (ssl_ftp_ctx != NULL) {
10194 SSL_CTX_free(ssl_ftp_ctx);
10195 ssl_ftp_ctx = NULL;
10196 }
10197
10198 /* The SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
10199 * was added to OpenSSL 0.9.6e and 0.9.7. It does not exist in previous
10200 * versions
10201 */
10202 #ifndef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
10203 #define SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS 0L
10204 #endif
10205 /*
10206 Pick allowed SSL/TLS versions according to enabled bugs.
10207 Modified 5 Feb 2015 to default to TLS 1.0 if no bugs are enabled,
10208 instead of to SSL 3.0, which has the POODLE vulnerability.
10209 */
10210 if (ftp_bug_use_ssl_v2) {
10211 /* allow SSL 2.0 or later */
10212 client_method = SSLv23_client_method();
10213 #ifndef OPENSSL_NO_SSL3
10214 } else if (ftp_bug_use_ssl_v3) {
10215 /* allow SSL 3.0 ONLY - previous default */
10216 client_method = SSLv3_client_method();
10217 #endif /* OPENSSL_NO_SSL3 */
10218 } else {
10219 /* default - allow TLS 1.0 or later */
10220 client_method = TLSv1_client_method();
10221 }
10222 if (auth_type && !strcmp(auth_type,"TLS")) {
10223 ssl_ftp_ctx=SSL_CTX_new(client_method);
10224 if (!ssl_ftp_ctx)
10225 return(0);
10226 SSL_CTX_set_options(ssl_ftp_ctx,
10227 SSL_OP_SINGLE_DH_USE|SSL_OP_EPHEMERAL_RSA
10228 );
10229 } else {
10230 ssl_ftp_ctx = SSL_CTX_new(client_method);
10231 if (!ssl_ftp_ctx)
10232 return(0);
10233 SSL_CTX_set_options(ssl_ftp_ctx,
10234 (ftp_bug_use_ssl_v2 ? 0 : SSL_OP_NO_SSLv2)|
10235 SSL_OP_SINGLE_DH_USE|SSL_OP_EPHEMERAL_RSA
10236 );
10237 }
10238 SSL_CTX_set_default_passwd_cb(ssl_ftp_ctx,
10239 (pem_password_cb *)ssl_passwd_callback);
10240 SSL_CTX_set_info_callback(ssl_ftp_ctx,ssl_client_info_callback);
10241 SSL_CTX_set_session_cache_mode(ssl_ftp_ctx,SSL_SESS_CACHE_CLIENT);
10242
10243 #ifdef OS2
10244 #ifdef NT
10245 /* The defaults in the SSL crypto library are not appropriate for OS/2 */
10246 {
10247 char path[CKMAXPATH];
10248 extern char exedir[];
10249
10250 ckmakmsg(path,CKMAXPATH,exedir,"certs",NULL,NULL);
10251 if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,NULL,path) == 0) {
10252 debug(F110,"ftp ssl_auth unable to load path",path,0);
10253 if (ssl_debug_flag)
10254 printf("?Unable to load verify-dir: %s\r\n",path);
10255 }
10256
10257 ckmakmsg(path,CKMAXPATH,
10258 (char *)GetAppData(1),"kermit 95/certs",NULL,NULL);
10259 if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,NULL,path) == 0) {
10260 debug(F110,"ftp ssl_auth unable to load path",path,0);
10261 if (ssl_debug_flag)
10262 printf("?Unable to load verify-dir: %s\r\n",path);
10263 }
10264
10265 ckmakmsg(path,CKMAXPATH,
10266 (char *)GetAppData(0),"kermit 95/certs",NULL,NULL);
10267 if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,NULL,path) == 0) {
10268 debug(F110,"ftp ssl_auth unable to load path",path,0);
10269 if (ssl_debug_flag)
10270 printf("?Unable to load verify-dir: %s\r\n",path);
10271 }
10272
10273 ckmakmsg(path,CKMAXPATH,exedir,"ca_certs.pem",NULL,NULL);
10274 if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,path,NULL) == 0) {
10275 debug(F110,"ftp ssl_auth unable to load path",path,0);
10276 if (ssl_debug_flag)
10277 printf("?Unable to load verify-file: %s\r\n",path);
10278 }
10279
10280 ckmakmsg(path,CKMAXPATH,(char *)GetAppData(1),
10281 "kermit 95/ca_certs.pem",NULL,NULL);
10282 if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,path,NULL) == 0) {
10283 debug(F110,"ftp ssl_auth unable to load path",path,0);
10284 if (ssl_debug_flag)
10285 printf("?Unable to load verify-file: %s\r\n",path);
10286 }
10287
10288 ckmakmsg(path,CKMAXPATH,(char *)GetAppData(0),
10289 "kermit 95/ca_certs.pem",NULL,NULL);
10290 if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,path,NULL) == 0) {
10291 debug(F110,"ftp ssl_auth unable to load path",path,0);
10292 if (ssl_debug_flag)
10293 printf("?Unable to load verify-file: %s\r\n",path);
10294 }
10295 }
10296 #else /* NT */
10297 /* The defaults in the SSL crypto library are not appropriate for OS/2 */
10298 {
10299
10300 char path[CKMAXPATH];
10301 extern char exedir[];
10302
10303 ckmakmsg(path,CKMAXPATH,exedir,"certs",NULL,NULL);
10304 if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,NULL,path) == 0) {
10305 debug(F110,"ftp ssl_auth unable to load path",path,0);
10306 if (ssl_debug_flag)
10307 printf("?Unable to load verify-dir: %s\r\n",path);
10308 }
10309 ckmakmsg(path,CKMAXPATH,exedir,"ca_certs.pem",NULL,NULL);
10310 if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,path,NULL) == 0) {
10311 debug(F110,"ftp ssl_auth unable to load path",path,0);
10312 if (ssl_debug_flag)
10313 printf("?Unable to load verify-file: %s\r\n",path);
10314 }
10315 }
10316 #endif /* NT */
10317 #else /* OS2 */
10318 SSL_CTX_set_default_verify_paths(ssl_ftp_ctx);
10319 #endif /* OS2 */
10320
10321 if (ssl_verify_file &&
10322 SSL_CTX_load_verify_locations(ssl_ftp_ctx,ssl_verify_file,NULL) == 0) {
10323 debug(F110,
10324 "ftp ssl auth unable to load ssl_verify_file",
10325 ssl_verify_file,
10326 0
10327 );
10328 if (ssl_debug_flag)
10329 printf("?Unable to load verify-file: %s\r\n",ssl_verify_file);
10330 }
10331 if (ssl_verify_dir &&
10332 SSL_CTX_load_verify_locations(ssl_ftp_ctx,NULL,ssl_verify_dir) == 0) {
10333 debug(F110,
10334 "ftp ssl auth unable to load ssl_verify_dir",
10335 ssl_verify_dir,
10336 0
10337 );
10338 if (ssl_debug_flag)
10339 printf("?Unable to load verify-dir: %s\r\n",ssl_verify_dir);
10340 }
10341
10342 /* set up the new CRL Store */
10343 crl_store = (X509_STORE *)X509_STORE_new();
10344 if (crl_store) {
10345 #ifdef OS2
10346 char path[CKMAXPATH];
10347 extern char exedir[];
10348
10349 ckmakmsg(path,CKMAXPATH,exedir,"crls",NULL,NULL);
10350 if (X509_STORE_load_locations(crl_store,NULL,path) == 0) {
10351 debug(F110,"ftp ssl auth unable to load dir",path,0);
10352 if (ssl_debug_flag)
10353 printf("?Unable to load crl-dir: %s\r\n",path);
10354 }
10355 #ifdef NT
10356 ckmakmsg(path,CKMAXPATH,
10357 (char *)GetAppData(1),"kermit 95/crls",NULL,NULL);
10358 if (X509_STORE_load_locations(crl_store,NULL,path) == 0) {
10359 debug(F110,"ftp ssl auth unable to load dir",path,0);
10360 if (ssl_debug_flag)
10361 printf("?Unable to load crl-dir: %s\r\n",path);
10362 }
10363 ckmakmsg(path,CKMAXPATH,
10364 (char *)GetAppData(0),"kermit 95/crls",NULL,NULL);
10365 if (X509_STORE_load_locations(crl_store,NULL,path) == 0) {
10366 debug(F110,"ftp ssl auth unable to load dir",path,0);
10367 if (ssl_debug_flag)
10368 printf("?Unable to load crl-dir: %s\r\n",path);
10369 }
10370 #endif /* NT */
10371
10372 ckmakmsg(path,CKMAXPATH,exedir,"ca_crls.pem",NULL,NULL);
10373 if (X509_STORE_load_locations(crl_store,path,NULL) == 0) {
10374 debug(F110,"ftp ssl auth unable to load file",path,0);
10375 if (ssl_debug_flag)
10376 printf("?Unable to load crl-file: %s\r\n",path);
10377 }
10378 #ifdef NT
10379 ckmakmsg(path,CKMAXPATH,(char *)GetAppData(1),
10380 "kermit 95/ca_crls.pem",NULL,NULL);
10381 if (X509_STORE_load_locations(crl_store,path,NULL) == 0) {
10382 debug(F110,"ftp ssl auth unable to load file",path,0);
10383 if (ssl_debug_flag)
10384 printf("?Unable to load crl-file: %s\r\n",path);
10385 }
10386 ckmakmsg(path,CKMAXPATH,(char *)GetAppData(0),
10387 "kermit 95/ca_crls.pem",NULL,NULL);
10388 if (X509_STORE_load_locations(crl_store,path,NULL) == 0) {
10389 debug(F110,"ftp ssl auth unable to load file",path,0);
10390 if (ssl_debug_flag)
10391 printf("?Unable to load crl-file: %s\r\n",path);
10392 }
10393 #endif /* NT */
10394 #endif /* OS2 */
10395
10396 if (ssl_crl_file || ssl_crl_dir) {
10397 if (ssl_crl_file &&
10398 X509_STORE_load_locations(crl_store,ssl_crl_file,NULL) == 0) {
10399 debug(F110,
10400 "ftp ssl auth unable to load ssl_crl_file",
10401 ssl_crl_file,
10402 0
10403 );
10404 if (ssl_debug_flag)
10405 printf("?Unable to load crl-file: %s\r\n",ssl_crl_file);
10406 }
10407 if (ssl_crl_dir &&
10408 X509_STORE_load_locations(crl_store,NULL,ssl_crl_dir) == 0) {
10409 debug(F110,
10410 "ftp ssl auth unable to load ssl_crl_dir",
10411 ssl_crl_dir,
10412 0
10413 );
10414 if (ssl_debug_flag)
10415 printf("?Unable to load crl-dir: %s\r\n",ssl_crl_dir);
10416 }
10417 } else {
10418 X509_STORE_set_default_paths(crl_store);
10419 }
10420 }
10421 SSL_CTX_set_verify(ssl_ftp_ctx,ssl_verify_flag,
10422 ssl_client_verify_callback);
10423 ssl_verify_depth = -1;
10424 ssl_ftp_con=(SSL *)SSL_new(ssl_ftp_ctx);
10425 tls_load_certs(ssl_ftp_ctx,ssl_ftp_con,0);
10426 SSL_set_fd(ssl_ftp_con,csocket);
10427 SSL_set_verify(ssl_ftp_con,ssl_verify_flag,NULL);
10428 if (ssl_cipher_list) {
10429 SSL_set_cipher_list(ssl_ftp_con,ssl_cipher_list);
10430 } else {
10431 char * p;
10432 if (p = getenv("SSL_CIPHER")) {
10433 SSL_set_cipher_list(ssl_ftp_con,p);
10434 } else {
10435 SSL_set_cipher_list(ssl_ftp_con,DEFAULT_CIPHER_LIST);
10436 }
10437 }
10438 if (ssl_debug_flag) {
10439 fprintf(stderr,"=>START SSL/TLS connect on COMMAND\n");
10440 fflush(stderr);
10441 }
10442 if (SSL_connect(ssl_ftp_con) <= 0) {
10443 static char errbuf[1024];
10444 ckmakmsg(errbuf,1024,"ftp: SSL/TLS connect COMMAND error: ",
10445 ERR_error_string(ERR_get_error(),NULL),NULL,NULL);
10446 fprintf(stderr,"%s\n", errbuf);
10447 fflush(stderr);
10448 ssl_ftp_active_flag=0;
10449 SSL_free(ssl_ftp_con);
10450 ssl_ftp_con = NULL;
10451 } else {
10452 ssl_ftp_active_flag = 1;
10453
10454 if (!ssl_certsok_flag &&
10455 (ssl_verify_flag & SSL_VERIFY_PEER) && /* JEA 2013-12-10 */
10456 !tls_is_krb5(1)) {
10457 char *subject = ssl_get_subject_name(ssl_ftp_con);
10458
10459 if (!subject) {
10460 if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
10461 debug(F110,"ssl_auth","[SSL - FAILED]",0);
10462 return(ssl_ftp_active_flag = 0);
10463 } else {
10464 if (uq_ok("Warning: Server didn't provide a certificate\n",
10465 "Continue? (Y/N)",3,NULL,0) <= 0) {
10466 debug(F110, "ssl_auth","[SSL - FAILED]",0);
10467 return(ssl_ftp_active_flag = 0);
10468 }
10469 }
10470 } else if (ssl_check_server_name(ssl_ftp_con, ftp_user_host)) {
10471 debug(F110,"ssl_auth","[SSL - FAILED]",0);
10472 return(ssl_ftp_active_flag = 0);
10473 }
10474 }
10475 debug(F110,"ssl_auth","[SSL - OK]",0);
10476 ssl_display_connect_details(ssl_ftp_con,0,ssl_verbose_flag);
10477 }
10478 if (ssl_debug_flag) {
10479 fprintf(stderr,"=>DONE SSL/TLS connect on COMMAND\n");
10480 fflush(stderr);
10481 }
10482 return(ssl_ftp_active_flag);
10483 }
10484 #endif /* CK_SSL */
10485
10486 static sigtype
cmdcancel(sig)10487 cmdcancel(sig) int sig; {
10488 #ifdef OS2
10489 /* In Unix we "chain" to trap(), which prints this */
10490 printf("^C...\n");
10491 #endif /* OS2 */
10492 debug(F100,"ftp cmdcancel caught SIGINT ","",0);
10493 fflush(stdout);
10494 secure_getc(0,1); /* Initialize net input buffers */
10495 cancelfile++;
10496 cancelgroup++;
10497 mlsreset();
10498 #ifndef OS2
10499 #ifdef FTP_PROXY
10500 if (ptflag) /* proxy... */
10501 longjmp(ptcancel,1);
10502 #endif /* FTP_PROXY */
10503 debug(F100,"ftp cmdcancel chain to trap()...","",0);
10504 trap(SIGINT);
10505 /* NOTREACHED */
10506 debug(F100,"ftp cmdcancel return from trap()...","",0);
10507 #else
10508 debug(F100,"ftp cmdcancel PostCtrlCSem()...","",0);
10509 PostCtrlCSem();
10510 #endif /* OS2 */
10511 }
10512
10513 static int
10514 #ifdef CK_ANSIC
scommand(char * s)10515 scommand(char * s) /* Was secure_command() */
10516 #else
10517 scommand(s) char * s;
10518 #endif /* CK_ANSIC */
10519 {
10520 int length = 0, len2;
10521 char in[FTP_BUFSIZ], out[FTP_BUFSIZ];
10522 #ifdef CK_SSL
10523 if (ssl_ftp_active_flag) {
10524 int error, rc;
10525 length = strlen(s) + 2;
10526 length = ckmakmsg(out,FTP_BUFSIZ,s,"\r\n",NULL,NULL);
10527 rc = SSL_write(ssl_ftp_con,out,length);
10528 error = SSL_get_error(ssl_ftp_con,rc);
10529 switch (error) {
10530 case SSL_ERROR_NONE:
10531 return(1);
10532 case SSL_ERROR_WANT_WRITE:
10533 case SSL_ERROR_WANT_READ:
10534 case SSL_ERROR_SYSCALL:
10535 #ifdef NT
10536 {
10537 int gle = GetLastError();
10538 }
10539 #endif /* NT */
10540 case SSL_ERROR_WANT_X509_LOOKUP:
10541 case SSL_ERROR_SSL:
10542 case SSL_ERROR_ZERO_RETURN:
10543 default:
10544 lostpeer();
10545 }
10546 return(0);
10547 }
10548 #endif /* CK_SSL */
10549
10550 if (auth_type && ftp_cpl != FPL_CLR) {
10551 #ifdef FTP_SRP
10552 if (ck_srp_is_installed() && (strcmp(auth_type,"SRP") == 0))
10553 if ((length = srp_encode(ftp_cpl == FPL_PRV,
10554 (CHAR *)s,
10555 (CHAR *)out,
10556 strlen(s))) < 0) {
10557 fprintf(stderr, "SRP failed to encode message\n");
10558 return(0);
10559 }
10560 #endif /* FTP_SRP */
10561 #ifdef FTP_KRB4
10562 if (ck_krb4_is_installed() &&
10563 (strcmp(auth_type, "KERBEROS_V4") == 0)) {
10564 if (ftp_cpl == FPL_PRV) {
10565 length =
10566 krb_mk_priv((CHAR *)s, (CHAR *)out,
10567 strlen(s), ftp_sched,
10568 #ifdef KRB524
10569 ftp_cred.session,
10570 #else /* KRB524 */
10571 &ftp_cred.session,
10572 #endif /* KRB524 */
10573 &myctladdr, &hisctladdr);
10574 } else {
10575 length =
10576 krb_mk_safe((CHAR *)s,
10577 (CHAR *)out,
10578 strlen(s),
10579 #ifdef KRB524
10580 ftp_cred.session,
10581 #else /* KRB524 */
10582 &ftp_cred.session,
10583 #endif /* KRB524 */
10584 &myctladdr, &hisctladdr);
10585 }
10586 if (length == -1) {
10587 fprintf(stderr, "krb_mk_%s failed for KERBEROS_V4\n",
10588 ftp_cpl == FPL_PRV ? "priv" : "safe");
10589 return(0);
10590 }
10591 }
10592 #endif /* FTP_KRB4 */
10593 #ifdef FTP_GSSAPI
10594 /* Scommand (based on level) */
10595 if (ck_gssapi_is_installed() && (strcmp(auth_type, "GSSAPI") == 0)) {
10596 gss_buffer_desc in_buf, out_buf;
10597 OM_uint32 maj_stat, min_stat;
10598 int conf_state;
10599 in_buf.value = s;
10600 in_buf.length = strlen(s) + 1;
10601 maj_stat = gss_seal(&min_stat, gcontext,
10602 (ftp_cpl==FPL_PRV), /* private */
10603 GSS_C_QOP_DEFAULT,
10604 &in_buf, &conf_state,
10605 &out_buf);
10606 if (maj_stat != GSS_S_COMPLETE) { /* Generally need to deal */
10607 user_gss_error(maj_stat, min_stat,
10608 (ftp_cpl==FPL_PRV)?
10609 "gss_seal ENC didn't complete":
10610 "gss_seal MIC didn't complete");
10611 } else if ((ftp_cpl == FPL_PRV) && !conf_state) {
10612 fprintf(stderr, "GSSAPI didn't encrypt message");
10613 } else {
10614 if (ftp_deb)
10615 fprintf(stderr, "sealed (%s) %d bytes\n",
10616 ftp_cpl==FPL_PRV?"ENC":"MIC",
10617 out_buf.length);
10618 memcpy(out, out_buf.value,
10619 length=out_buf.length);
10620 gss_release_buffer(&min_stat, &out_buf);
10621 }
10622 }
10623 #endif /* FTP_GSSAPI */
10624 /* Other auth types go here ... */
10625
10626 len2 = FTP_BUFSIZ;
10627 if ((kerror = radix_encode((CHAR *)out, (CHAR *)in,
10628 length, &len2, RADIX_ENCODE))
10629 ) {
10630 fprintf(stderr,"Couldn't base 64 encode command (%s)\n",
10631 radix_error(kerror));
10632 return(0);
10633 }
10634 if (ftp_deb)
10635 fprintf(stderr, "scommand(%s)\nencoding %d bytes\n", s, length);
10636 len2 = ckmakmsg(out,
10637 FTP_BUFSIZ,
10638 ftp_cpl == FPL_PRV ? "ENC " : "MIC ",
10639 in,
10640 "\r\n",
10641 NULL
10642 );
10643 send(csocket,(SENDARG2TYPE)out,len2,0);
10644 } else {
10645 char out[FTP_BUFSIZ];
10646 int len = ckmakmsg(out,FTP_BUFSIZ,s,"\r\n",NULL,NULL);
10647 send(csocket,(SENDARG2TYPE)out,len,0);
10648 }
10649 return(1);
10650 }
10651
10652 static int
mygetc()10653 mygetc() {
10654 static char inbuf[4096];
10655 static int bp = 0, ep = 0;
10656 int rc;
10657
10658 if (bp == ep) {
10659 bp = ep = 0;
10660 #ifdef CK_SSL
10661 if (ssl_ftp_active_flag) {
10662 int error;
10663 rc = SSL_read(ssl_ftp_con,inbuf,4096);
10664 error = SSL_get_error(ssl_ftp_con,rc);
10665 switch (error) {
10666 case SSL_ERROR_NONE:
10667 break;
10668 case SSL_ERROR_WANT_WRITE:
10669 case SSL_ERROR_WANT_READ:
10670 return(0);
10671 case SSL_ERROR_SYSCALL:
10672 if (rc == 0) { /* EOF */
10673 break;
10674 } else {
10675 #ifdef NT
10676 int gle = GetLastError();
10677 #endif /* NT */
10678 break;
10679 }
10680 case SSL_ERROR_WANT_X509_LOOKUP:
10681 case SSL_ERROR_SSL:
10682 case SSL_ERROR_ZERO_RETURN:
10683 default:
10684 break;
10685 }
10686 } else
10687 #endif /* CK_SSL */
10688 rc = recv(csocket,(char *)inbuf,4096,0);
10689 if (rc <= 0)
10690 return(EOF);
10691 ep = rc;
10692 }
10693 return(inbuf[bp++]);
10694 }
10695
10696 /* x l a t e c -- Translate a character */
10697 /*
10698 Call with:
10699 fc = Function code: 0 = translate, 1 = initialize.
10700 c = Character (as int).
10701 incs = Index of charset to translate from.
10702 outcs = Index of charset to translate to.
10703
10704 Returns:
10705 0: OK
10706 -1: Error
10707 */
10708 static int
xlatec(fc,c,incs,outcs)10709 xlatec(fc,c,incs,outcs) int fc, c, incs, outcs; {
10710 #ifdef NOCSETS
10711 return(c);
10712 #else
10713 static char buf[128];
10714 static int cx;
10715 int c0, c1;
10716
10717 if (fc == 1) { /* Initialize */
10718 cx = 0; /* Catch-up buffer write index */
10719 xgnbp = buf; /* Catch-up buffer read pointer */
10720 buf[0] = NUL; /* Buffer is empty */
10721 return(0);
10722 }
10723 if (cx >= 127) { /* Catch-up buffer full */
10724 debug(F100,"xlatec overflow","",0); /* (shouldn't happen) */
10725 printf("?Translation buffer overflow\n");
10726 return(-1);
10727 }
10728 /* Add char to buffer. */
10729 /* The buffer won't grow unless incs is a multibyte set, e.g. UTF-8. */
10730
10731 debug(F000,"xlatec buf",ckitoa(cx),c);
10732 buf[cx++] = c;
10733 buf[cx] = NUL;
10734
10735 while ((c0 = xgnbyte(FC_UCS2,incs,strgetc)) > -1) {
10736 if (xpnbyte(c0,TC_UCS2,outcs,NULL) < 0) /* (NULL was xprintc) */
10737 return(-1);
10738 }
10739 /* If we're caught up, reinitialize the buffer */
10740 return((cx == (xgnbp - buf)) ? xlatec(1,0,0,0) : 0);
10741 #endif /* NOCSETS */
10742 }
10743
10744
10745 /* p a r s e f e a t */
10746
10747 /* Note: for convenience we align keyword values with table indices */
10748 /* If you need to insert a new keyword, adjust the SFT_xxx definitions */
10749
10750 static struct keytab feattab[] = {
10751 { "$$$$", 0, 0 }, /* Dummy for sfttab[0] */
10752 { "AUTH", SFT_AUTH, 0 },
10753 { "LANG", SFT_LANG, 0 },
10754 { "MDTM", SFT_MDTM, 0 },
10755 { "MLST", SFT_MLST, 0 },
10756 { "PBSZ", SFT_PBSZ, 0 },
10757 { "PROT", SFT_PROT, 0 },
10758 { "REST", SFT_REST, 0 },
10759 { "SIZE", SFT_SIZE, 0 },
10760 { "TVFS", SFT_TVFS, 0 },
10761 { "UTF8", SFT_UTF8, 0 }
10762 };
10763 static int nfeattab = (sizeof(feattab) / sizeof(struct keytab));
10764
10765 #define FACT_CSET 1
10766 #define FACT_CREA 2
10767 #define FACT_LANG 3
10768 #define FACT_MTYP 4
10769 #define FACT_MDTM 5
10770 #define FACT_PERM 6
10771 #define FACT_SIZE 7
10772 #define FACT_TYPE 8
10773 #define FACT_UNIQ 9
10774
10775 static struct keytab facttab[] = {
10776 { "CHARSET", FACT_CSET, 0 },
10777 { "CREATE", FACT_CREA, 0 },
10778 { "LANG", FACT_LANG, 0 },
10779 { "MEDIA-TYPE", FACT_MTYP, 0 },
10780 { "MODIFY", FACT_MDTM, 0 },
10781 { "PERM", FACT_PERM, 0 },
10782 { "SIZE", FACT_SIZE, 0 },
10783 { "TYPE", FACT_TYPE, 0 },
10784 { "UNIQUE", FACT_UNIQ, 0 }
10785 };
10786 static int nfacttab = (sizeof(facttab) / sizeof(struct keytab));
10787
10788 static struct keytab ftyptab[] = {
10789 { "CDIR", FTYP_CDIR, 0 },
10790 { "DIR", FTYP_DIR, 0 },
10791 { "FILE", FTYP_FILE, 0 },
10792 { "PDIR", FTYP_PDIR, 0 }
10793 };
10794 static int nftyptab = (sizeof(ftyptab) / sizeof(struct keytab));
10795
10796 static VOID
parsefeat(s)10797 parsefeat(s) char * s; { /* Parse a FEATURE response */
10798 char kwbuf[8];
10799 int i, x;
10800 if (!s) return;
10801 if (!*s) return;
10802 while (*s < '!')
10803 s++;
10804 for (i = 0; i < 4; i++) {
10805 if (s[i] < '!')
10806 break;
10807 kwbuf[i] = s[i];
10808 }
10809 if (s[i] && s[i] != SP && s[i] != CR && s[i] != LF)
10810 return;
10811 kwbuf[i] = NUL;
10812 /* xlookup requires a full (but case independent) match */
10813 i = xlookup(feattab,kwbuf,nfeattab,&x);
10814 debug(F111,"ftp parsefeat",s,i);
10815 if (i < 0 || i > 15)
10816 return;
10817
10818 switch (i) {
10819 case SFT_MDTM: /* Controlled by ENABLE/DISABLE */
10820 sfttab[i] = mdtmok;
10821 if (mdtmok) sfttab[0]++;
10822 break;
10823 case SFT_MLST: /* ditto */
10824 sfttab[i] = mlstok;
10825 if (mlstok) sfttab[0]++;
10826 break;
10827 case SFT_SIZE: /* ditto */
10828 sfttab[i] = sizeok;
10829 if (sizeok) sfttab[0]++;
10830 break;
10831 case SFT_AUTH: /* ditto */
10832 sfttab[i] = ftp_aut;
10833 if (ftp_aut) sfttab[0]++;
10834 break;
10835 default: /* Others */
10836 sfttab[0]++;
10837 sfttab[i]++;
10838 }
10839 }
10840
10841 static char *
parsefacts(s)10842 parsefacts(s) char * s; { /* Parse MLS[DT] File Facts */
10843 char * p;
10844 int i, j, x;
10845 if (!s) return(NULL);
10846 if (!*s) return(NULL);
10847
10848 /* Maybe we should make a copy of s so we can poke it... */
10849
10850 while ((p = ckstrchr(s,'='))) {
10851 *p = NUL; /* s points to fact */
10852 i = xlookup(facttab,s,nfacttab,&x);
10853 debug(F111,"ftp parsefact fact",s,i);
10854 *p = '=';
10855 s = p+1; /* Now s points to arg */
10856 p = ckstrchr(s,';');
10857 if (!p)
10858 p = ckstrchr(s,SP);
10859 if (!p) {
10860 debug(F110,"ftp parsefact end-of-val search fail",s,0);
10861 break;
10862 }
10863 *p = NUL;
10864 debug(F110,"ftp parsefact valu",s,0);
10865 switch (i) {
10866 case FACT_CSET: /* Ignore these for now */
10867 case FACT_CREA:
10868 case FACT_LANG:
10869 case FACT_PERM:
10870 case FACT_MTYP:
10871 case FACT_UNIQ:
10872 break;
10873 case FACT_MDTM: /* Modtime */
10874 makestr(&havemdtm,s);
10875 debug(F110,"ftp parsefact mdtm",havemdtm,0);
10876 break;
10877 case FACT_SIZE: /* Size */
10878 havesize = ckatofs(s);
10879 debug(F101,"ftp parsefact size","",havesize);
10880 break;
10881 case FACT_TYPE: /* Type */
10882 j = xlookup(ftyptab,s,nftyptab,NULL);
10883 debug(F111,"ftp parsefact type",s,j);
10884 havetype = (j < 1) ? 0 : j;
10885 break;
10886 }
10887 *p = ';';
10888 s = p+1; /* s points next fact or name */
10889 }
10890 while (*s == SP) /* Skip past spaces. */
10891 s++;
10892 if (!*s) /* Make sure we still have a name */
10893 s = NULL;
10894 debug(F110,"ftp parsefact name",s,0);
10895 return(s);
10896 }
10897
10898 /* g e t r e p l y -- (to an FTP command sent to server) */
10899
10900 /* vbm = 1 (verbose); 0 (quiet except for error messages); 9 (super quiet) */
10901
10902 static int
getreply(expecteof,lcs,rcs,vbm,fc)10903 getreply(expecteof,lcs,rcs,vbm,fc) int expecteof, lcs, rcs, vbm, fc; {
10904 /* lcs, rcs, vbm parameters as in ftpcmd() */
10905 register int i, c, n;
10906 register int dig;
10907 register char *cp;
10908 int xlate = 0;
10909 int count = 0;
10910 int auth = 0;
10911 int originalcode = 0, continuation = 0;
10912 sig_t oldintr;
10913 int pflag = 0;
10914 char *pt = pasv;
10915 char ibuf[FTP_BUFSIZ], obuf[FTP_BUFSIZ]; /* (these are pretty big...) */
10916 int safe = 0;
10917 int xquiet = 0;
10918
10919 auth = (fc == GRF_AUTH);
10920
10921 #ifndef NOCSETS
10922 debug(F101,"ftp getreply lcs","",lcs);
10923 debug(F101,"ftp getreply rcs","",rcs);
10924 if (lcs > -1 && rcs > -1 && lcs != rcs) {
10925 xlate = 1;
10926 initxlate(rcs,lcs);
10927 xlatec(1,0,rcs,lcs);
10928 }
10929 #endif /* NOCSETS */
10930 debug(F101,"ftp getreply fc","",fc);
10931
10932 if (quiet)
10933 xquiet = 1;
10934 if (vbm == 9) {
10935 xquiet = 1;
10936 vbm = 0;
10937 }
10938 if (ftp_deb) /* DEBUG */
10939 vbm = 1;
10940 else if (quiet || dpyactive) /* QUIET or File Transfer Active */
10941 vbm = 0;
10942 else if (vbm < 0) /* VERBOSE */
10943 vbm = ftp_vbm;
10944
10945 ibuf[0] = '\0';
10946 if (reply_parse)
10947 reply_ptr = reply_buf;
10948 havesigint = 0;
10949 oldintr = signal(SIGINT, cmdcancel);
10950 for (count = 0;; count++) {
10951 obuf[0] = '\0';
10952 dig = n = ftpcode = i = 0;
10953 cp = ftp_reply_str;
10954 while ((c = ibuf[0] ? ibuf[i++] : mygetc()) != '\n') {
10955 if (c == IAC) { /* Handle telnet commands */
10956 switch (c = mygetc()) {
10957 case WILL:
10958 case WONT:
10959 c = mygetc();
10960 obuf[0] = IAC;
10961 obuf[1] = DONT;
10962 obuf[2] = c;
10963 obuf[3] = NUL;
10964 #ifdef CK_SSL
10965 if (ssl_ftp_active_flag) {
10966 int error, rc;
10967 rc = SSL_write(ssl_ftp_con,obuf,3);
10968 error = SSL_get_error(ssl_ftp_con,rc);
10969 switch (error) {
10970 case SSL_ERROR_NONE:
10971 break;
10972 case SSL_ERROR_WANT_WRITE:
10973 case SSL_ERROR_WANT_READ:
10974 return(0);
10975 case SSL_ERROR_SYSCALL:
10976 if (rc == 0) { /* EOF */
10977 break;
10978 } else {
10979 #ifdef NT
10980 int gle = GetLastError();
10981 #endif /* NT */
10982 break;
10983 }
10984 case SSL_ERROR_WANT_X509_LOOKUP:
10985 case SSL_ERROR_SSL:
10986 case SSL_ERROR_ZERO_RETURN:
10987 default:
10988 break;
10989 }
10990 } else
10991 #endif /* CK_SSL */
10992 send(csocket,(SENDARG2TYPE)obuf,3,0);
10993 break;
10994 case DO:
10995 case DONT:
10996 c = mygetc();
10997 obuf[0] = IAC;
10998 obuf[1] = WONT;
10999 obuf[2] = c;
11000 obuf[3] = NUL;
11001 #ifdef CK_SSL
11002 if (ssl_ftp_active_flag) {
11003 int error, rc;
11004 rc = SSL_write(ssl_ftp_con,obuf,3);
11005 error = SSL_get_error(ssl_ftp_con,rc);
11006 switch (error) {
11007 case SSL_ERROR_NONE:
11008 break;
11009 case SSL_ERROR_WANT_WRITE:
11010 case SSL_ERROR_WANT_READ:
11011 signal(SIGINT,oldintr);
11012 return(0);
11013 case SSL_ERROR_SYSCALL:
11014 if (rc == 0) { /* EOF */
11015 break;
11016 } else {
11017 #ifdef NT
11018 int gle = GetLastError();
11019 #endif /* NT */
11020 break;
11021 }
11022 case SSL_ERROR_WANT_X509_LOOKUP:
11023 case SSL_ERROR_SSL:
11024 case SSL_ERROR_ZERO_RETURN:
11025 default:
11026 break;
11027 }
11028 } else
11029 #endif /* CK_SSL */
11030 send(csocket,(SENDARG2TYPE)obuf,3,0);
11031 break;
11032 default:
11033 break;
11034 }
11035 continue;
11036 }
11037 dig++;
11038 if (c == EOF) {
11039 if (expecteof) {
11040 signal(SIGINT,oldintr);
11041 ftpcode = 221;
11042 debug(F101,"ftp getreply EOF","",ftpcode);
11043 return(0);
11044 }
11045 lostpeer();
11046 if (!xquiet) {
11047 if (ftp_deb)
11048 printf("421 ");
11049 printf(
11050 "Service not available, connection closed by server\n");
11051 fflush(stdout);
11052 }
11053 signal(SIGINT,oldintr);
11054 ftpcode = 421;
11055 debug(F101,"ftp getreply EOF","",ftpcode);
11056 return(4);
11057 }
11058 if (n == 0) { /* First digit */
11059 n = c; /* Save it */
11060 }
11061 if (auth_type &&
11062 #ifdef CK_SSL
11063 !ssl_ftp_active_flag &&
11064 #endif /* CK_SSL */
11065 !ibuf[0] && (n == '6' || continuation)) {
11066 if (c != '\r' && dig > 4)
11067 obuf[i++] = c;
11068 } else {
11069 if (auth_type &&
11070 #ifdef CK_SSL
11071 !ssl_ftp_active_flag &&
11072 #endif /* CK_SSL */
11073 !ibuf[0] && dig == 1 && vbm)
11074 printf("Unauthenticated reply received from server:\n");
11075 if (reply_parse) {
11076 *reply_ptr++ = c;
11077 *reply_ptr = NUL;
11078 }
11079 if ((!dpyactive || ftp_deb) && /* Don't mess up xfer display */
11080 ftp_cmdlin < 2) {
11081 if ((c != '\r') &&
11082 (ftp_deb || ((vbm || (!auth && n == '5')) &&
11083 (dig > 4 || ( dig <= 4 && !isdigit(c) && ftpcode == 0
11084 )))))
11085 {
11086 #ifdef FTP_PROXY
11087 if (ftp_prx && (dig == 1 || (dig == 5 && vbm == 0)))
11088 printf("%s:",ftp_host);
11089 #endif /* FTP_PROXY */
11090
11091 if (!xquiet) {
11092 #ifdef NOCSETS
11093 printf("%c",c);
11094 #else
11095 if (xlate) {
11096 xlatec(0,c,rcs,lcs);
11097 } else {
11098 printf("%c",c);
11099 }
11100 #endif /* NOCSETS */
11101 }
11102 }
11103 }
11104 }
11105 if (auth_type &&
11106 #ifdef CK_SSL
11107 !ssl_ftp_active_flag &&
11108 #endif /* CK_SSL */
11109 !ibuf[0] && n != '6')
11110 continue;
11111 if (dig < 4 && isdigit(c))
11112 ftpcode = ftpcode * 10 + (c - '0');
11113 if (!pflag && ftpcode == 227)
11114 pflag = 1;
11115 if (dig > 4 && pflag == 1 && isdigit(c))
11116 pflag = 2;
11117 if (pflag == 2) {
11118 if (c != '\r' && c != ')')
11119 *pt++ = c;
11120 else {
11121 *pt = '\0';
11122 pflag = 3;
11123 }
11124 }
11125 if (dig == 4 && c == '-' && n != '6') {
11126 if (continuation)
11127 ftpcode = 0;
11128 continuation++;
11129 }
11130 if (cp < &ftp_reply_str[FTP_BUFSIZ - 1]) {
11131 *cp++ = c;
11132 *cp = NUL;
11133 }
11134 }
11135 if (deblog ||
11136 #ifdef COMMENT
11137 /*
11138 Sometimes we need to print the server reply. printlines is nonzero for any
11139 command where the results are sent back on the control connection rather
11140 than the data connection, e.g. STAT. In the TOPS-20 case, each file line
11141 has ftpcode 213. But if you do this with a UNIX server, it sends "213-Start
11142 STAT", <line with ftpcode == 0>, "213-End" or somesuch. So when printlines
11143 is nonzero, we want the 213 lines from TOPS-20 and we DON'T want the 213
11144 lines from UNIX. Further experimentation needed with other servers. Of
11145 course RFC959 is mute as to the format of the server reply.
11146
11147 'printlines' is also true for PWD and BYE.
11148 */
11149 (printlines && ((ftpcode == 0) || (servertype == SYS_TOPS20)))
11150 #else
11151 /* No, we can't be that clever -- it breaks other things like RPWD... */
11152 (printlines &&
11153 (ftpcode != 631 && ftpcode != 632 && ftpcode != 633))
11154 #endif /* COMMENT */
11155 ) {
11156 char * q = cp;
11157 char *r = ftp_reply_str;
11158 *q-- = NUL; /* NUL-terminate */
11159 while (*q < '!' && q > r) /* Strip CR, etc */
11160 *q-- = NUL;
11161 if (!ftp_deb && printlines) { /* If printing */
11162 if (ftpcode != 0) /* strip ftpcode if any */
11163 r += 4;
11164 #ifdef NOCSETS
11165 printf("%s\n",r); /* and print */
11166 #else
11167 if (!xlate) {
11168 printf("%s\n",r);
11169 } else { /* Translating */
11170 xgnbp = r; /* Set up strgetc() */
11171 while ((c0 = xgnbyte(FC_UCS2,rcs,strgetc)) > -1) {
11172 if (xpnbyte(c0,TC_UCS2,lcs,NULL) < 0) { /* (xprintc) */
11173 signal(SIGINT,oldintr);
11174 return(-1);
11175 }
11176 }
11177 printf("\n");
11178 }
11179 #endif /* NOCSETS */
11180 }
11181 }
11182 debug(F110,"FTP RCVD ",ftp_reply_str,0);
11183
11184 if (fc == GRF_FEAT) { /* Parsing FEAT command response? */
11185 if (count == 0 && n == '2') {
11186 int i; /* (Re)-init server FEATure table */
11187 debug(F100,"ftp getreply clearing feature table","",0);
11188 for (i = 0; i < 16; i++)
11189 sfttab[i] = 0;
11190 } else {
11191 parsefeat((char *)ftp_reply_str);
11192 }
11193 }
11194 if (auth_type &&
11195 #ifdef CK_SSL
11196 !ssl_ftp_active_flag &&
11197 #endif /* CK_SSL */
11198 !ibuf[0] && n != '6') {
11199 signal(SIGINT,oldintr);
11200 return(getreply(expecteof,lcs,rcs,vbm,auth));
11201 }
11202 ibuf[0] = obuf[i] = '\0';
11203 if (ftpcode && n == '6')
11204 if (ftpcode != 631 && ftpcode != 632 && ftpcode != 633) {
11205 printf("Unknown reply: %d %s\n", ftpcode, obuf);
11206 n = '5';
11207 } else safe = (ftpcode == 631);
11208 if (obuf[0] /* if there is a string to decode */
11209 #ifdef CK_SSL
11210 && !ssl_ftp_active_flag /* and not SSL/TLS */
11211 #endif /* CK_SSL */
11212 ) {
11213 if (!auth_type) {
11214 printf("Cannot decode reply:\n%d %s\n", ftpcode, obuf);
11215 n = '5';
11216 }
11217 #ifndef CK_ENCRYPTION
11218 else if (ftpcode == 632) {
11219 printf("Cannot decrypt %d reply: %s\n", ftpcode, obuf);
11220 n = '5';
11221 }
11222 #endif /* CK_ENCRYPTION */
11223 #ifdef NOCONFIDENTIAL
11224 else if (ftpcode == 633) {
11225 printf("Cannot decrypt %d reply: %s\n", ftpcode, obuf);
11226 n = '5';
11227 }
11228 #endif /* NOCONFIDENTIAL */
11229 else {
11230 int len = FTP_BUFSIZ;
11231 if ((kerror = radix_encode((CHAR *)obuf,
11232 (CHAR *)ibuf,
11233 0,
11234 &len,
11235 RADIX_DECODE))
11236 ) {
11237 printf("Can't decode base 64 reply %d (%s)\n\"%s\"\n",
11238 ftpcode, radix_error(kerror), obuf);
11239 n = '5';
11240 }
11241 #ifdef FTP_SRP
11242 else if (strcmp(auth_type, "SRP") == 0) {
11243 int outlen;
11244 outlen = srp_decode(!safe, (CHAR *)ibuf,
11245 (CHAR *) ibuf, len);
11246 if (outlen < 0) {
11247 printf("Warning: %d reply %s!\n",
11248 ftpcode, safe ? "modified" : "garbled");
11249 n = '5';
11250 } else {
11251 ckstrncpy(&ibuf[outlen], "\r\n",FTP_BUFSIZ-outlen);
11252 if (ftp_deb)
11253 printf("%c:", safe ? 'S' : 'P');
11254 continue;
11255 }
11256 }
11257 #endif /* FTP_SRP */
11258 #ifdef FTP_KRB4
11259 else if (strcmp(auth_type, "KERBEROS_V4") == 0) {
11260 if (safe) {
11261 kerror = krb_rd_safe((CHAR *)ibuf, len,
11262 #ifdef KRB524
11263 ftp_cred.session,
11264 #else /* KRB524 */
11265 &ftp_cred.session,
11266 #endif /* KRB524 */
11267 &hisctladdr,
11268 &myctladdr,
11269 &ftp_msg_data
11270 );
11271 } else {
11272 kerror = krb_rd_priv((CHAR *)ibuf, len,
11273 ftp_sched,
11274 #ifdef KRB524
11275 ftp_cred.session,
11276 #else /* KRB524 */
11277 &ftp_cred.session,
11278 #endif /* KRB524 */
11279 &hisctladdr,
11280 &myctladdr,
11281 &ftp_msg_data
11282 );
11283 }
11284 if (kerror != KSUCCESS) {
11285 printf("%d reply %s! (krb_rd_%s: %s)\n", ftpcode,
11286 safe ? "modified" : "garbled",
11287 safe ? "safe" : "priv",
11288 krb_get_err_text(kerror));
11289 n = '5';
11290 } else if (ftp_msg_data.app_length >= FTP_BUFSIZ - 3) {
11291 kerror = KFAILURE;
11292 n = '5';
11293 printf("reply data too large for buffer\n");
11294 } else {
11295 if (ftp_deb)
11296 printf("%c:", safe ? 'S' : 'P');
11297 memcpy(ibuf,ftp_msg_data.app_data,
11298 ftp_msg_data.app_length);
11299 ckstrncpy(&ibuf[ftp_msg_data.app_length], "\r\n",
11300 FTP_BUFSIZ - ftp_msg_data.app_length);
11301 continue;
11302 }
11303 }
11304 #endif /* FTP_KRB4 */
11305 #ifdef FTP_GSSAPI
11306 else if (strcmp(auth_type, "GSSAPI") == 0) {
11307 gss_buffer_desc xmit_buf, msg_buf;
11308 OM_uint32 maj_stat, min_stat;
11309 int conf_state;
11310 xmit_buf.value = ibuf;
11311 xmit_buf.length = len;
11312 /* decrypt/verify the message */
11313 conf_state = safe;
11314 maj_stat = gss_unseal(&min_stat, gcontext,
11315 &xmit_buf, &msg_buf,
11316 &conf_state, NULL);
11317 if (maj_stat != GSS_S_COMPLETE) {
11318 user_gss_error(maj_stat, min_stat,
11319 "failed unsealing reply");
11320 n = '5';
11321 } else {
11322 memcpy(ibuf, msg_buf.value, msg_buf.length);
11323 ckstrncpy(&ibuf[msg_buf.length], "\r\n",
11324 FTP_BUFSIZ-msg_buf.length);
11325 gss_release_buffer(&min_stat,&msg_buf);
11326 if (ftp_deb)
11327 printf("%c:", safe ? 'S' : 'P');
11328 continue;
11329 }
11330 }
11331 #endif /* FTP_GSSAPI */
11332 /* Other auth types go here... */
11333 }
11334 } else if ((!dpyactive || ftp_deb) && ftp_cmdlin < 2 &&
11335 !xquiet && (vbm || (!auth && (n == '4' || n == '5')))) {
11336 #ifdef NOCSETS
11337 printf("%c",c);
11338 #else
11339 if (xlate) {
11340 xlatec(0,c,rcs,lcs);
11341 } else {
11342 printf("%c",c);
11343 }
11344 #endif /* NOCSETS */
11345 fflush (stdout);
11346 }
11347 if (continuation && ftpcode != originalcode) {
11348 if (originalcode == 0)
11349 originalcode = ftpcode;
11350 continue;
11351 }
11352 *cp = '\0';
11353 if (n != '1')
11354 cpend = 0;
11355 signal(SIGINT,oldintr);
11356 if (ftpcode == 421 || originalcode == 421) {
11357 lostpeer();
11358 if (!xquiet && !ftp_deb)
11359 printf("%s\n",reply_buf);
11360 }
11361 if ((cancelfile != 0) &&
11362 #ifndef ULTRIX3
11363 /* Ultrix 3.0 cc objects violently to this clause */
11364 (oldintr != cmdcancel) &&
11365 #endif /* ULTRIX3 */
11366 (oldintr != SIG_IGN)) {
11367 if (oldintr)
11368 (*oldintr)(SIGINT);
11369 }
11370 if (reply_parse) {
11371 *reply_ptr = '\0';
11372 if ((reply_ptr = ckstrstr(reply_buf, reply_parse))) {
11373 reply_parse = reply_ptr + strlen(reply_parse);
11374 if ((reply_ptr = ckstrpbrk(reply_parse, " \r")))
11375 *reply_ptr = '\0';
11376 } else
11377 reply_parse = reply_ptr;
11378 }
11379 while (*cp < '!' && cp > ftp_reply_str) /* Remove trailing junk */
11380 *cp-- = NUL;
11381 debug(F111,"ftp getreply",ftp_reply_str,n - '0');
11382 return(n - '0');
11383 } /* for (;;) */
11384 }
11385
11386 #ifdef BSDSELECT
11387 static int
11388 #ifdef CK_ANSIC
empty(fd_set * mask,int sec)11389 empty(fd_set * mask, int sec)
11390 #else
11391 empty(mask, sec) fd_set * mask; int sec;
11392 #endif /* CK_ANSIC */
11393 {
11394 struct timeval t;
11395 t.tv_sec = (long) sec;
11396 t.tv_usec = 0L;
11397 debug(F100,"ftp empty calling select...","",0);
11398 #ifdef INTSELECT
11399 x = select(32, (int *)mask, NULL, NULL, &t);
11400 #else
11401 x = select(32, mask, (fd_set *) 0, (fd_set *) 0, &t);
11402 #endif /* INTSELECT */
11403 debug(F101,"ftp empty select","",x);
11404 return(x);
11405 }
11406 #else /* BSDSELECT */
11407 #ifdef IBMSELECT
11408 static int
empty(mask,cnt,sec)11409 empty(mask, cnt, sec) int * mask, sec;
11410 int cnt;
11411 {
11412 return(select(mask,cnt,0,0,sec*1000));
11413 }
11414 #endif /* IBMSELECT */
11415 #endif /* BSDSELECT */
11416
11417 static sigtype
cancelsend(sig)11418 cancelsend(sig) int sig; {
11419 havesigint++;
11420 cancelgroup++;
11421 cancelfile = 0;
11422 printf(" Canceled...\n");
11423 secure_getc(0,1); /* Initialize net input buffers */
11424 debug(F100,"ftp cancelsend caught SIGINT ","",0);
11425 fflush(stdout);
11426 #ifndef OS2
11427 longjmp(sendcancel, 1);
11428 #else
11429 PostCtrlCSem();
11430 #endif /* OS2 */
11431 }
11432
11433 static VOID
11434 #ifdef CK_ANSIC
secure_error(char * fmt,...)11435 secure_error(char *fmt, ...)
11436 #else
11437 /* VARARGS1 */
11438 secure_error(fmt, p1, p2, p3, p4, p5)
11439 char *fmt; int p1, p2, p3, p4, p5;
11440 #endif /* CK_ANSIC */
11441 {
11442 #ifdef CK_ANSIC
11443 va_list ap;
11444
11445 va_start(ap, fmt);
11446 vfprintf(stderr, fmt, ap);
11447 va_end(ap);
11448 #else
11449 fprintf(stderr, fmt, p1, p2, p3, p4, p5);
11450 #endif
11451 fprintf(stderr, "\n");
11452 }
11453
11454 /*
11455 * Internal form of settype; changes current type in use with server
11456 * without changing our notion of the type for data transfers.
11457 * Used to change to and from ascii for listings.
11458 */
11459 static VOID
changetype(newtype,show)11460 changetype(newtype, show) int newtype, show; {
11461 int rc;
11462 char * s;
11463
11464 if ((newtype == curtype) && typesent++)
11465 return;
11466 switch (newtype) {
11467 case FTT_ASC:
11468 s = "A";
11469 break;
11470 case FTT_BIN:
11471 s = "I";
11472 break;
11473 case FTT_TEN:
11474 s = "L 8";
11475 break;
11476 default:
11477 s = "I";
11478 break;
11479 }
11480 rc = ftpcmd("TYPE",s,-1,-1,show);
11481 if (rc == REPLY_COMPLETE)
11482 curtype = newtype;
11483 }
11484
11485 /* PUT a file. Returns -1 on error, 0 on success, 1 if file skipped */
11486
11487 static VOID
11488 #ifdef CK_ANSIC
doftpsend(void * threadinfo)11489 doftpsend(void * threadinfo)
11490 #else
11491 doftpsend(threadinfo) VOID * threadinfo;
11492 #endif
11493 {
11494 #ifdef NTSIG
11495 if (threadinfo) { /* Thread local storage... */
11496 TlsSetValue(TlsIndex,threadinfo);
11497 debug(F100, "doftpsend called with threadinfo block","", 0);
11498 } else debug(F100, "doftpsend - threadinfo is NULL", "", 0);
11499 #endif /* NTSIG */
11500 #ifdef CK_LOGIN
11501 #ifdef IKSD
11502 #ifdef NT
11503 if (inserver)
11504 setntcreds();
11505 #endif /* NT */
11506 #endif /* IKSD */
11507 #endif /* CK_LOGIN */
11508
11509 if (initconn()) {
11510 #ifndef NOHTTP
11511 int y = -1;
11512 /* debug(F101,"doftpsend","tcp_http_proxy",tcp_http_proxy); */
11513
11514 /* If the connection failed and we are using an HTTP Proxy
11515 * and the reason for the failure was an authentication
11516 * error, then we need to give the user to ability to
11517 * enter a username and password, just like a browser.
11518 *
11519 * I tried to do all of this within the netopen() call
11520 * but it is much too much work.
11521 */
11522 while (y != 0 && tcp_http_proxy != NULL ) {
11523
11524 if (tcp_http_proxy_errno == 401 ||
11525 tcp_http_proxy_errno == 407 ) {
11526 char uid[UIDBUFLEN];
11527 char pwd[PWDSIZ];
11528 struct txtbox tb[2];
11529 int ok;
11530
11531 tb[0].t_buf = uid;
11532 tb[0].t_len = UIDBUFLEN;
11533 tb[0].t_lbl = "Proxy Userid: ";
11534 tb[0].t_dflt = NULL;
11535 tb[0].t_echo = 1;
11536 tb[1].t_buf = pwd;
11537 tb[1].t_len = 256;
11538 tb[1].t_lbl = "Proxy Passphrase: ";
11539 tb[1].t_dflt = NULL;
11540 tb[1].t_echo = 2;
11541
11542 ok = uq_mtxt("Proxy Server Authentication Required\n",
11543 NULL, 2, tb);
11544 if (ok && uid[0]) {
11545 char * proxy_user, * proxy_pwd;
11546
11547 proxy_user = tcp_http_proxy_user;
11548 proxy_pwd = tcp_http_proxy_pwd;
11549
11550 tcp_http_proxy_user = uid;
11551 tcp_http_proxy_pwd = pwd;
11552
11553 y = initconn();
11554
11555 debug(F101,"doftpsend","initconn",y);
11556 memset(pwd,0,PWDSIZ);
11557 tcp_http_proxy_user = proxy_user;
11558 tcp_http_proxy_pwd = proxy_pwd;
11559 } else
11560 break;
11561 } else
11562 break;
11563 }
11564
11565 if ( y != 0 ) {
11566 #endif /* NOHTTP */
11567 signal(SIGINT, ftpsnd.oldintr);
11568 #ifdef SIGPIPE
11569 if (ftpsnd.oldintp)
11570 signal(SIGPIPE, ftpsnd.oldintp);
11571 #endif /* SIGPIPE */
11572 ftpcode = -1;
11573 zclose(ZIFILE);
11574 ftpsndret = -1;
11575 #ifdef NTSIG
11576 ckThreadEnd(threadinfo);
11577 #endif /* NTSIG */
11578 return;
11579 #ifndef NOHTTP
11580 }
11581 #endif /* NOHTTP */
11582 }
11583 ftpsndret = 0;
11584 #ifdef NTSIG
11585 ckThreadEnd(threadinfo);
11586 #endif /* NTSIG */
11587 }
11588
11589 static VOID
11590 #ifdef CK_ANSIC
failftpsend(void * threadinfo)11591 failftpsend(void * threadinfo)
11592 #else
11593 failftpsend(threadinfo) VOID * threadinfo;
11594 #endif /* CK_ANSIC */
11595 {
11596 #ifdef NTSIG
11597 if (threadinfo) { /* Thread local storage... */
11598 TlsSetValue(TlsIndex,threadinfo);
11599 debug(F100, "docmdfile called with threadinfo block","", 0);
11600 } else debug(F100, "docmdfile - threadinfo is NULL", "", 0);
11601 #endif /* NTSIG */
11602 #ifdef CK_LOGIN
11603 #ifdef IKSD
11604 #ifdef NT
11605 if (inserver)
11606 setntcreds();
11607 #endif /* NT */
11608 #endif /* IKSD */
11609 #endif /* CK_LOGIN */
11610
11611 while (cpend) {
11612 ftpsnd.reply = getreply(0,ftpsnd.incs,ftpsnd.outcs,ftp_vbm,0);
11613 debug(F111,"ftp sendrequest getreply","null command",ftpsnd.reply);
11614 }
11615 if (data >= 0) {
11616 #ifdef CK_SSL
11617 if (ssl_ftp_data_active_flag) {
11618 SSL_shutdown(ssl_ftp_data_con);
11619 SSL_free(ssl_ftp_data_con);
11620 ssl_ftp_data_active_flag = 0;
11621 ssl_ftp_data_con = NULL;
11622 }
11623 #endif /* CK_SSL */
11624 #ifdef TCPIPLIB
11625 socket_close(data);
11626 #else /* TCPIPLIB */
11627 #ifdef USE_SHUTDOWN
11628 shutdown(data, 1+1);
11629 #endif /* USE_SHUTDOWN */
11630 close(data);
11631 #endif /* TCPIPLIB */
11632 data = -1;
11633 globaldin = -1;
11634 }
11635 if (ftpsnd.oldintr)
11636 signal(SIGINT,ftpsnd.oldintr);
11637 #ifdef SIGPIPE
11638 if (ftpsnd.oldintp)
11639 signal(SIGPIPE,ftpsnd.oldintp);
11640 #endif /* SIGPIPE */
11641 ftpcode = -1;
11642 #ifndef OS2
11643 /* TEST ME IN K95 */
11644 if (havesigint) {
11645 havesigint = 0;
11646 debug(F100,"ftp failftpsend chain to trap()...","",0);
11647 if (ftpsnd.oldintr != SIG_IGN)
11648 (*ftpsnd.oldintr)(SIGINT);
11649 /* NOTREACHED (I hope!) */
11650 debug(F100,"ftp failftpsend return from trap()...","",0);
11651 }
11652 #endif /* OS2 */
11653 }
11654
11655 static VOID
11656 #ifdef CK_ANSIC
failftpsend2(void * threadinfo)11657 failftpsend2(void * threadinfo)
11658 #else
11659 failftpsend2(threadinfo) VOID * threadinfo;
11660 #endif /* CK_ANSIC */
11661 {
11662 #ifdef NTSIG
11663 if (threadinfo) { /* Thread local storage... */
11664 TlsSetValue(TlsIndex,threadinfo);
11665 debug(F100, "docmdfile called with threadinfo block","", 0);
11666 } else debug(F100, "docmdfile - threadinfo is NULL", "", 0);
11667 #endif /* NTSIG */
11668 #ifdef CK_LOGIN
11669 #ifdef IKSD
11670 #ifdef NT
11671 if (inserver)
11672 setntcreds();
11673 #endif /* NT */
11674 #endif /* IKSD */
11675 #endif /* CK_LOGIN */
11676
11677 debug(F101,"ftp sendrequest canceled","",ftpsnd.bytes);
11678 tfc += ffc;
11679 #ifdef GFTIMER
11680 fpfsecs = gftimer();
11681 #endif /* GFTIMER */
11682 zclose(ZIFILE);
11683 #ifdef PIPESEND
11684 if (sndfilter)
11685 pipesend = 0;
11686 #endif /* PIPESEND */
11687 signal(SIGINT, ftpsnd.oldintr);
11688 #ifdef SIGPIPE
11689 if (ftpsnd.oldintp)
11690 signal(SIGPIPE, ftpsnd.oldintp);
11691 #endif /* SIGPIPE */
11692 if (!cpend) {
11693 ftpcode = -1;
11694 ftpsndret = -1;
11695 #ifdef NTSIG
11696 ckThreadEnd(threadinfo);
11697 #endif /* NTSIG */
11698 return;
11699 }
11700 if (data >= 0) {
11701 #ifdef CK_SSL
11702 if (ssl_ftp_data_active_flag) {
11703 SSL_shutdown(ssl_ftp_data_con);
11704 SSL_free(ssl_ftp_data_con);
11705 ssl_ftp_data_active_flag = 0;
11706 ssl_ftp_data_con = NULL;
11707 }
11708 #endif /* CK_SSL */
11709 #ifdef TCPIPLIB
11710 socket_close(data);
11711 #else /* TCPIPLIB */
11712 #ifdef USE_SHUTDOWN
11713 shutdown(data, 1+1);
11714 #endif /* USE_SHUTDOWN */
11715 close(data);
11716 #endif /* TCPIPLIB */
11717 data = -1;
11718 globaldin = -1;
11719 }
11720 if (dout) {
11721 #ifdef TCPIPLIB
11722 socket_close(dout);
11723 #else /* TCPIPLIB */
11724 #ifdef USE_SHUTDOWN
11725 shutdown(dout, 1+1);
11726 #endif /* USE_SHUTDOWN */
11727 close(dout);
11728 #endif /* TCPIPLIB */
11729 }
11730 ftpsnd.reply = getreply(0,ftpsnd.incs,ftpsnd.outcs,ftp_vbm,0);
11731 ftpcode = -1;
11732 ftpsndret = -1;
11733
11734 #ifndef OS2
11735 /* TEST ME IN K95 */
11736 if (havesigint) {
11737 havesigint = 0;
11738 debug(F100,"ftp failftpsend2 chain to trap()...","",0);
11739 if (ftpsnd.oldintr != SIG_IGN)
11740 (*ftpsnd.oldintr)(SIGINT);
11741 /* NOTREACHED (I hope!) */
11742 debug(F100,"ftp failftpsend2 return from trap()...","",0);
11743 }
11744 #endif /* OS2 */
11745 }
11746
11747 static VOID
11748 #ifdef CK_ANSIC
doftpsend2(void * threadinfo)11749 doftpsend2(void * threadinfo)
11750 #else
11751 doftpsend2(threadinfo) VOID * threadinfo;
11752 #endif
11753 {
11754 register int c, d = 0;
11755 int n, t, x, notafile, unique = 0;
11756 char *buf, *bufp;
11757
11758 #ifdef NTSIG
11759 if (threadinfo) { /* Thread local storage... */
11760 TlsSetValue(TlsIndex,threadinfo);
11761 debug(F100, "doftpsend2 called with threadinfo block","", 0);
11762 } else debug(F100, "doftpsend2 - threadinfo is NULL", "", 0);
11763 #endif /* NTSIG */
11764 #ifdef CK_LOGIN
11765 #ifdef IKSD
11766 #ifdef NT
11767 if (inserver)
11768 setntcreds();
11769 #endif /* NT */
11770 #endif /* IKSD */
11771 #endif /* CK_LOGIN */
11772
11773 buf = ftpsndbuf; /* (not on stack) */
11774
11775 unique = strcmp(ftpsnd.cmd,"STOU") ? 0 : 1;
11776 notafile = sndarray || pipesend;
11777
11778 #ifdef FTP_RESTART
11779 if (ftpsnd.restart && ((curtype == FTT_BIN) || (alike > 0))) {
11780 char * p;
11781 changetype(FTT_BIN,0); /* Change to binary */
11782
11783 /* Ask for remote file's size */
11784 x = ftpcmd("SIZE",ftpsnd.remote,ftpsnd.incs,ftpsnd.outcs,ftp_vbm);
11785
11786 if (x == REPLY_COMPLETE) { /* Have ftpsnd.reply */
11787 p = &ftp_reply_str[4]; /* Parse it */
11788 while (isdigit(*p)) {
11789 sendstart = sendstart * 10 + (int)(*p - '0');
11790 p++;
11791 }
11792 if (*p && *p != CR) { /* Bad number */
11793 debug(F110,"doftpsend2 bad size",ftp_reply_str,0);
11794 sendstart = (CK_OFF_T)0;
11795 } else if (sendstart > fsize) { /* Remote file bigger than local */
11796 debug(F110,"doftpsend2 big size",ckfstoa(fsize),sendstart);
11797 sendstart = (CK_OFF_T)0;
11798 }
11799 /* Local is newer */
11800 debug(F111,"doftpsend2 size",ftpsnd.remote,sendstart);
11801 if (chkmodtime(ftpsnd.local,ftpsnd.remote,0) == 2) {
11802 debug(F110,"doftpsend2 date mismatch",ftp_reply_str,0);
11803 sendstart = (CK_OFF_T)0; /* Send the whole file */
11804 }
11805 }
11806 changetype(ftp_typ,0); /* Change back to appropriate type */
11807 if (sendstart > (CK_OFF_T)0) { /* Still restarting? */
11808 if (sendstart == fsize) { /* Same size - no need to send */
11809 debug(F111,"doftpsend2 /restart SKIP",
11810 ckfstoa(fsize),sendstart);
11811 zclose(ZIFILE);
11812 ftpsndret = SKP_RES;
11813 #ifdef NTSIG
11814 ckThreadEnd(threadinfo);
11815 #endif /* NTSIG */
11816 return;
11817 }
11818 errno = 0; /* Restart needed, seek to the spot */
11819 if (zfseek((long)sendstart) < 0) {
11820 debug(F111,"doftpsend2 zfseek fails",
11821 ftpsnd.local,sendstart);
11822 fprintf(stderr, "FSEEK: %s: %s\n", ftpsnd.local, ck_errstr());
11823 sendstart = 0;
11824 zclose(ZIFILE);
11825 ftpsndret = -1;
11826 #ifdef NTSIG
11827 ckThreadEnd(threadinfo);
11828 #endif /* NTSIG */
11829 return;
11830 }
11831 #ifdef COMMENT
11832 debug(F111,"doftpsend2 zfseek ok",ftpsnd.local,sendstart);
11833 x = ftpcmd("REST",ckltoa(sendstart),-1,-1,ftp_vbm);
11834 if (x != REPLY_CONTINUE) {
11835 sendstart = 0;
11836 zclose(ZIFILE);
11837 ftpsndret = -1;
11838 #ifdef NTSIG
11839 ckThreadEnd(threadinfo);
11840 #endif /* NTSIG */
11841 return;
11842 } else {
11843 ftpsnd.cmd = "STOR";
11844 }
11845 #else
11846 sendmode = SM_RESEND;
11847 ftpsnd.cmd = "APPE";
11848 #endif /* COMMENT */
11849 /* sendstart = (CK_OFF_T)0; */
11850 }
11851 }
11852 #endif /* FTP_RESTART */
11853
11854 if (unique && !stouarg) /* If we know STOU accepts no arg */
11855 ftpsnd.remote = NULL; /* don't include one. */
11856
11857 x = ftpcmd(ftpsnd.cmd, ftpsnd.remote, ftpsnd.incs, ftpsnd.outcs, ftp_vbm);
11858 debug(F111,"doftpsend2 ftpcode",ftpsnd.cmd,ftpcode);
11859 debug(F101,"doftpsend2 ftpcmd","",x);
11860
11861 if (x != REPLY_PRELIM && unique) {
11862 /*
11863 RFC959 says STOU does not take an argument. But every FTP server
11864 I've encountered but one accepts the arg and constructs the unique
11865 name from it, which is better than making up a totally random name
11866 for the file, which is what RFC959 calls for. Especially because
11867 there is no way for the client to find out the name chosen by the
11868 server. So we try STOU with the argument first, which works with
11869 most servers, and if it fails we retry it without the arg, for
11870 the benefit of the one picky server that is not "liberal in what
11871 it accepts" UNLESS the first STOU got a 502 code ("not implemented")
11872 which means STOU is not accepted, period.
11873 */
11874 if ((x == 5) && stouarg && (ftpcode != 502)) {
11875 x = ftpcmd(ftpsnd.cmd,NULL,ftpsnd.incs,ftpsnd.outcs,ftp_vbm);
11876 if (x == REPLY_PRELIM) /* If accepted */
11877 stouarg = 0; /* flag no STOU arg for this server */
11878 }
11879 }
11880 if (x != REPLY_PRELIM) {
11881 signal(SIGINT, ftpsnd.oldintr);
11882 #ifdef SIGPIPE
11883 if (ftpsnd.oldintp)
11884 signal(SIGPIPE, ftpsnd.oldintp);
11885 #endif /* SIGPIPE */
11886 debug(F101,"doftpsend2 not REPLY_PRELIM","",x);
11887 zclose(ZIFILE);
11888 #ifdef PIPESEND
11889 if (sndfilter)
11890 pipesend = 0;
11891 #endif /* PIPESEND */
11892 ftpsndret = -1;
11893 #ifdef NTSIG
11894 ckThreadEnd(threadinfo);
11895 #endif /* NTSIG */
11896 return;
11897 }
11898 debug(F100,"doftpsend2 getting data connection...","",0);
11899 dout = dataconn(ftpsnd.lmode); /* Get data connection */
11900 debug(F101,"doftpsend2 dataconn","",dout);
11901 if (dout == -1) {
11902 failftpsend2(threadinfo);
11903 #ifdef NTSIG
11904 ckThreadEnd(threadinfo);
11905 #endif /* NTSIG */
11906 return;
11907 }
11908 /* Initialize per-file stats */
11909 ffc = (CK_OFF_T)0; /* Character counter */
11910 cps = oldcps = 0L; /* Thruput */
11911 n = 0;
11912 #ifdef GFTIMER
11913 rftimer(); /* reset f.p. timer */
11914 #endif /* GFTIMER */
11915
11916 #ifdef SIGPIPE
11917 ftpsnd.oldintp = signal(SIGPIPE, SIG_IGN);
11918 #endif /* SIGPIPE */
11919 debug(F101,"doftpsend2 curtype","",curtype);
11920 switch (curtype) {
11921 case FTT_BIN: /* Binary mode */
11922 case FTT_TEN:
11923 errno = d = 0;
11924 #ifdef VMS
11925 /*
11926 This is because VMS zxin() is C-Library fread()
11927 but the file was opened with zopeni(), which is RMS.
11928 */
11929 while (((c = zminchar()) > -1) && !cancelfile) {
11930 ffc++;
11931 if (zzout(dout,c) < 0)
11932 break;
11933 }
11934 #else /* VMS */
11935 while ((n = zxin(ZIFILE,buf,FTP_BUFSIZ - 1)) > 0 && !cancelfile) {
11936 ftpsnd.bytes += n;
11937 ffc += n;
11938 debug(F111,"doftpsend2 zxin",ckltoa(n),ffc);
11939 ckhexdump("doftpsend2 zxin",buf,16);
11940 #ifdef CK_SSL
11941 if (ssl_ftp_data_active_flag) {
11942 for (bufp = buf; n > 0; n -= d, bufp += d) {
11943 if ((d = SSL_write(ssl_ftp_data_con, bufp, n)) <= 0)
11944 break;
11945 spackets++;
11946 pktnum++;
11947 if (fdispla != XYFD_B) {
11948 spktl = d;
11949 ftscreen(SCR_PT,'D',(CK_OFF_T)spackets,NULL);
11950 }
11951 }
11952 } else {
11953 #endif /* CK_SSL */
11954 for (bufp = buf; n > 0; n -= d, bufp += d) {
11955 if (((d = secure_write(dout, (CHAR *)bufp, n)) <= 0)
11956 || iscanceled())
11957 break;
11958 spackets++;
11959 pktnum++;
11960 if (fdispla != XYFD_B) {
11961 spktl = d;
11962 ftscreen(SCR_PT,'D',(CK_OFF_T)spackets,NULL);
11963 }
11964 }
11965 #ifdef CK_SSL
11966 }
11967 #endif /* CK_SSL */
11968 if (d <= 0)
11969 break;
11970 }
11971 #endif /* VMS */
11972
11973 debug(F111,"doftpsend2 XX zxin",ckltoa(n),ffc);
11974 if (n < 0)
11975 fprintf(stderr, "local: %s: %s\n", ftpsnd.local, ck_errstr());
11976 if (d < 0 || (d = secure_flush(dout)) < 0) {
11977 if (d == -1 && errno && errno != EPIPE)
11978 perror("netout");
11979 ftpsnd.bytes = -1;
11980 }
11981 break;
11982
11983 case FTT_ASC: /* Text mode */
11984 #ifndef NOCSETS
11985 if (ftpsnd.xlate) { /* With translation */
11986 initxlate(ftpsnd.incs,ftpsnd.outcs);
11987 while (!cancelfile) {
11988 if ((c0 = xgnbyte(FC_UCS2,ftpsnd.incs,NULL)) < 0) break;
11989 if ((x = xpnbyte(c0,TC_UCS2,ftpsnd.outcs,xxout)) < 0) break;
11990 }
11991 } else {
11992 #endif /* NOCSETS */
11993 /* Text mode, no translation */
11994 while (((c = zminchar()) > -1) && !cancelfile) {
11995 ffc++;
11996 if (xxout(c) < 0)
11997 break;
11998 }
11999 d = 0;
12000 #ifndef NOCSETS
12001 }
12002 #endif /* NOCSETS */
12003 if (dout == -1 || (d = secure_flush(dout)) < 0) {
12004 if (d == -1 && errno && errno != EPIPE)
12005 perror("netout");
12006 ftpsnd.bytes = -1;
12007 }
12008 break;
12009 }
12010 tfc += ffc; /* Total file chars */
12011 #ifdef GFTIMER
12012 fpfsecs = gftimer();
12013 #endif /* GFTIMER */
12014 zclose(ZIFILE); /* Close input file */
12015 #ifdef PIPESEND
12016 if (sndfilter) /* Undo this (it's per file) */
12017 pipesend = 0;
12018 #endif /* PIPESEND */
12019
12020 #ifdef CK_SSL
12021 if (ssl_ftp_data_active_flag) {
12022 SSL_shutdown(ssl_ftp_data_con);
12023 SSL_free(ssl_ftp_data_con);
12024 ssl_ftp_data_active_flag = 0;
12025 ssl_ftp_data_con = NULL;
12026 }
12027 #endif /* CK_SSL */
12028
12029 #ifdef TCPIPLIB
12030 socket_close(dout); /* Close data connection */
12031 #else /* TCPIPLIB */
12032 #ifdef USE_SHUTDOWN
12033 shutdown(dout, 1+1);
12034 #endif /* USE_SHUTDOWN */
12035 close(dout);
12036 #endif /* TCPIPLIB */
12037 ftpsnd.reply = getreply(0,ftpsnd.incs,ftpsnd.outcs,ftp_vbm,0);
12038 signal(SIGINT, ftpsnd.oldintr); /* Put back interrupts */
12039 #ifdef SIGPIPE
12040 if (ftpsnd.oldintp)
12041 signal(SIGPIPE, ftpsnd.oldintp);
12042 #endif /* SIGPIPE */
12043 if (ftpsnd.reply == REPLY_TRANSIENT || ftpsnd.reply == REPLY_ERROR) {
12044 debug(F101,"doftpsend2 ftpsnd.reply","",ftpsnd.reply);
12045 ftpsndret = -1;
12046 #ifdef NTSIG
12047 ckThreadEnd(threadinfo);
12048 #endif /* NTSIG */
12049 return;
12050 } else if (cancelfile) {
12051 debug(F101,"doftpsend2 canceled","",ftpsnd.bytes);
12052 ftpsndret = -1;
12053 #ifdef NTSIG
12054 ckThreadEnd(threadinfo);
12055 #endif /* NTSIG */
12056 return;
12057 }
12058 debug(F101,"doftpsend2 ok","",ftpsnd.bytes);
12059 ftpsndret = 0;
12060 #ifdef NTSIG
12061 ckThreadEnd(threadinfo);
12062 #endif /* NTSIG */
12063 }
12064
12065 static int
sendrequest(cmd,local,remote,xlate,incs,outcs,restart)12066 sendrequest(cmd, local, remote, xlate, incs, outcs, restart)
12067 char *cmd, *local, *remote; int xlate, incs, outcs, restart;
12068 {
12069 if (!remote) remote = ""; /* Check args */
12070 if (!*remote) remote = local;
12071 if (!local) local = "";
12072 if (!*local) return(-1);
12073 if (!cmd) cmd = "";
12074 if (!*cmd) cmd = "STOR";
12075
12076 debug(F111,"ftp sendrequest restart",local,restart);
12077
12078 nout = 0; /* Init output buffer count */
12079 ftpsnd.bytes = 0; /* File input byte count */
12080 dout = -1;
12081
12082 #ifdef FTP_PROXY
12083 if (proxy) {
12084 proxtrans(cmd, local, remote, !strcmp(cmd,"STOU"));
12085 return(0);
12086 }
12087 #endif /* FTP_PROXY */
12088
12089 changetype(ftp_typ,0); /* Change type for this file */
12090
12091 ftpsnd.oldintr = NULL; /* Set up interrupt handler */
12092 ftpsnd.oldintp = NULL;
12093 ftpsnd.restart = restart;
12094 ftpsnd.xlate = xlate;
12095 ftpsnd.lmode = "wb";
12096
12097 #ifdef PIPESEND /* Use Kermit API for file i/o... */
12098 if (sndfilter) {
12099 char * p = NULL, * q;
12100 #ifndef NOSPL
12101 int n = CKMAXPATH;
12102 if (cmd_quoting && (p = (char *) malloc(n + 1))) {
12103 q = p;
12104 debug(F110,"sendrequest pipesend filter",sndfilter,0);
12105 zzstring(sndfilter,&p,&n);
12106 debug(F111,"sendrequest pipename",q,n);
12107 if (n <= 0) {
12108 printf("?Sorry, send filter + filename too long, %d max.\n",
12109 CKMAXPATH
12110 );
12111 free(q);
12112 return(-1);
12113 }
12114 ckstrncpy(filnam,q,CKMAXPATH+1);
12115 free(q);
12116 local = filnam;
12117 }
12118 #endif /* NOSPL */
12119 }
12120
12121 if (sndfilter) /* If sending thru a filter */
12122 pipesend = 1; /* set this for open and i/o */
12123 #endif /* PIPESEND */
12124
12125 #ifdef VMS
12126 debug(F101,"XXX before openi binary","",binary);
12127 debug(F101,"XXX before openi ftp_typ","",ftp_typ);
12128 #endif /* VMS */
12129
12130 if (openi(local) == 0) /* Try to open the input file */
12131 return(-1);
12132
12133 #ifdef VMS
12134 debug(F101,"XXX after openi binary","",binary);
12135 debug(F101,"XXX after openi ftp_typ","",ftp_typ);
12136 if (!forcetype) {
12137 if (binary != ftp_typ) { /* VMS zopeni() sets binary */
12138 debug(F101,"XXX changing type","",binary);
12139 doftptyp(binary);
12140 debug(F101,"XXX after doftptyp","",ftp_typ);
12141
12142 /* **** */
12143 if (displa && fdispla) { /* Update file type display */
12144 ftscreen(SCR_FN,'F',(CK_OFF_T)0,local);
12145 }
12146 }
12147 }
12148 #endif /* VMS */
12149 ftpsndret = 0;
12150 ftpsnd.incs = incs;
12151 ftpsnd.outcs = outcs;
12152 ftpsnd.cmd = cmd;
12153 ftpsnd.local = local;
12154 ftpsnd.remote = remote;
12155 ftpsnd.oldintr = signal(SIGINT, cancelsend);
12156 havesigint = 0;
12157
12158 if (cc_execute(ckjaddr(sendcancel), doftpsend, failftpsend) < 0)
12159 return(-1);
12160 if (ftpsndret < 0)
12161 return(-1);
12162 if (cc_execute(ckjaddr(sendcancel), doftpsend2, failftpsend2) < 0)
12163 return(-1);
12164
12165 return(ftpsndret);
12166 }
12167
12168 static sigtype
cancelrecv(sig)12169 cancelrecv(sig) int sig; {
12170 havesigint++;
12171 cancelfile = 0;
12172 cancelgroup++;
12173 secure_getc(0,1); /* Initialize net input buffers */
12174 printf(" Canceling...\n");
12175 debug(F100,"ftp cancelrecv caught SIGINT","",0);
12176 fflush(stdout);
12177 if (fp_nml) {
12178 if (fp_nml != stdout)
12179 fclose(fp_nml);
12180 fp_nml = NULL;
12181 }
12182 #ifndef OS2
12183 longjmp(recvcancel, 1);
12184 #else
12185 PostCtrlCSem();
12186 #endif /* OS2 */
12187 }
12188
12189 /* Argumentless front-end for secure_getc() */
12190
12191 static int
netgetc()12192 netgetc() {
12193 return(secure_getc(globaldin,0));
12194 }
12195
12196 /* Returns -1 on failure, 0 on success, 1 if file skipped */
12197
12198 /*
12199 Sets ftpcode < 0 on failure if failure reason is not server reply code:
12200 -1: interrupted by user.
12201 -2: error opening or writing output file (reason in errno).
12202 -3: failure to make data connection.
12203 -4: network read error (reason in errno).
12204 */
12205
12206 struct xx_ftprecv {
12207 int reply;
12208 int fcs;
12209 int rcs;
12210 int recover;
12211 int xlate;
12212 int din;
12213 int is_retr;
12214 sig_t oldintr, oldintp;
12215 char * cmd;
12216 char * local;
12217 char * remote;
12218 char * lmode;
12219 char * pipename;
12220 int tcrflag;
12221 CK_OFF_T localsize;
12222 };
12223 static struct xx_ftprecv ftprecv;
12224
12225 static int ftprecvret = 0;
12226
12227 static VOID
12228 #ifdef CK_ANSIC
failftprecv(VOID * threadinfo)12229 failftprecv(VOID * threadinfo)
12230 #else
12231 failftprecv(threadinfo) VOID * threadinfo;
12232 #endif /* CK_ANSIC */
12233 {
12234 #ifdef NTSIG
12235 if (threadinfo) { /* Thread local storage... */
12236 TlsSetValue(TlsIndex,threadinfo);
12237 debug(F100, "docmdfile called with threadinfo block","", 0);
12238 } else debug(F100, "docmdfile - threadinfo is NULL", "", 0);
12239 #endif /* NTSIG */
12240
12241 #ifdef CK_LOGIN
12242 #ifdef IKSD
12243 #ifdef NT
12244 if (inserver)
12245 setntcreds();
12246 #endif /* NT */
12247 #endif /* IKSD */
12248 #endif /* CK_LOGIN */
12249
12250 while (cpend) {
12251 ftprecv.reply = getreply(0,ftprecv.fcs,ftprecv.rcs,ftp_vbm,0);
12252 }
12253 if (data >= 0) {
12254 #ifdef CK_SSL
12255 if (ssl_ftp_data_active_flag) {
12256 SSL_shutdown(ssl_ftp_data_con);
12257 SSL_free(ssl_ftp_data_con);
12258 ssl_ftp_data_active_flag = 0;
12259 ssl_ftp_data_con = NULL;
12260 }
12261 #endif /* CK_SSL */
12262 #ifdef TCPIPLIB
12263 socket_close(data);
12264 #else /* TCPIPLIB */
12265 #ifdef USE_SHUTDOWN
12266 shutdown(data, 1+1);
12267 #endif /* USE_SHUTDOWN */
12268 close(data);
12269 #endif /* TCPIPLIB */
12270 data = -1;
12271 globaldin = -1;
12272 }
12273 if (ftprecv.oldintr)
12274 signal(SIGINT, ftprecv.oldintr);
12275 ftpcode = -1;
12276 ftprecvret = -1;
12277
12278 #ifndef OS2
12279 /* TEST ME IN K95 */
12280 if (havesigint) {
12281 havesigint = 0;
12282 debug(F100,"ftp failftprecv chain to trap()...","",0);
12283 if (ftprecv.oldintr != SIG_IGN)
12284 (*ftprecv.oldintr)(SIGINT);
12285 /* NOTREACHED (I hope!) */
12286 debug(F100,"ftp failftprecv return from trap()...","",0);
12287 }
12288 #endif /* OS2 */
12289 return;
12290 }
12291
12292 static VOID
12293 #ifdef CK_ANSIC
doftprecv(VOID * threadinfo)12294 doftprecv(VOID * threadinfo)
12295 #else
12296 doftprecv(threadinfo) VOID * threadinfo;
12297 #endif /* CK_ANSIC */
12298 {
12299 #ifdef NTSIG
12300 if (threadinfo) { /* Thread local storage... */
12301 TlsSetValue(TlsIndex,threadinfo);
12302 debug(F100, "docmdfile called with threadinfo block","", 0);
12303 } else debug(F100, "docmdfile - threadinfo is NULL", "", 0);
12304 #endif /* NTSIG */
12305 #ifdef CK_LOGIN
12306 #ifdef IKSD
12307 #ifdef NT
12308 if (inserver)
12309 setntcreds();
12310 #endif /* NT */
12311 #endif /* IKSD */
12312 #endif /* CK_LOGIN */
12313
12314 #ifndef COMMENT
12315 if (!out2screen && !ftprecv.pipename) {
12316 int x;
12317 char * local;
12318 local = ftprecv.local;
12319 x = zchko(local);
12320 if (x < 0) {
12321 if ((!dpyactive || ftp_deb))
12322 fprintf(stderr,
12323 "Temporary file %s: %s\n", ftprecv.local, ck_errstr());
12324 signal(SIGINT, ftprecv.oldintr);
12325 ftpcode = -2;
12326 ftprecvret = -1;
12327 #ifdef NTSIG
12328 ckThreadEnd(threadinfo);
12329 #endif /* NTSIG */
12330 return;
12331 }
12332 }
12333 #endif /* COMMENT */
12334 changetype((!ftprecv.is_retr) ? FTT_ASC : ftp_typ, 0);
12335 if (initconn()) { /* Initialize the data connection */
12336 signal(SIGINT, ftprecv.oldintr);
12337 ftpcode = -1;
12338 ftprecvret = -3;
12339 #ifdef NTSIG
12340 ckThreadEnd(threadinfo);
12341 #endif /* NTSIG */
12342 return;
12343 }
12344 secure_getc(0,1); /* Initialize net input buffers */
12345 ftprecvret = 0;
12346
12347 #ifdef NTSIG
12348 ckThreadEnd(threadinfo);
12349 #endif /* NTSIG */
12350 }
12351
12352 static VOID
12353 #ifdef CK_ANSIC
failftprecv2(VOID * threadinfo)12354 failftprecv2(VOID * threadinfo)
12355 #else
12356 failftprecv2(threadinfo) VOID * threadinfo;
12357 #endif /* CK_ANSIC */
12358 {
12359 #ifdef NTSIG
12360 if (threadinfo) { /* Thread local storage... */
12361 TlsSetValue(TlsIndex,threadinfo);
12362 debug(F100, "docmdfile called with threadinfo block","", 0);
12363 } else debug(F100, "docmdfile - threadinfo is NULL", "", 0);
12364 #endif /* NTSIG */
12365 #ifdef CK_LOGIN
12366 #ifdef IKSD
12367 #ifdef NT
12368 if (inserver)
12369 setntcreds();
12370 #endif /* NT */
12371 #endif /* IKSD */
12372 #endif /* CK_LOGIN */
12373
12374 /* Cancel using RFC959 recommended IP,SYNC sequence */
12375
12376 debug(F100,"ftp recvrequest CANCEL","",0);
12377 #ifdef GFTIMER
12378 fpfsecs = gftimer();
12379 #endif /* GFTIMER */
12380 #ifdef SIGPIPE
12381 if (ftprecv.oldintp)
12382 signal(SIGPIPE, ftprecv.oldintr);
12383 #endif /* SIGPIPE */
12384 signal(SIGINT, SIG_IGN);
12385 if (!cpend) {
12386 ftpcode = -1;
12387 signal(SIGINT, ftprecv.oldintr);
12388 ftprecvret = -1;
12389 #ifdef NTSIG
12390 ckThreadEnd(threadinfo);
12391 #endif /* NTSIG */
12392 return;
12393 }
12394 cancel_remote(ftprecv.din);
12395
12396 #ifdef FTP_TIMEOUT
12397 if (ftp_timed_out && out2screen && !quiet)
12398 printf("\n?Timed out.\n");
12399 #endif /* FTP_TIMEOUT */
12400
12401 if (ftpcode > -1)
12402 ftpcode = -1;
12403 if (data >= 0) {
12404 #ifdef CK_SSL
12405 if (ssl_ftp_data_active_flag) {
12406 SSL_shutdown(ssl_ftp_data_con);
12407 SSL_free(ssl_ftp_data_con);
12408 ssl_ftp_data_active_flag = 0;
12409 ssl_ftp_data_con = NULL;
12410 }
12411 #endif /* CK_SSL */
12412 #ifdef TCPIPLIB
12413 socket_close(data);
12414 #else /* TCPIPLIB */
12415 #ifdef USE_SHUTDOWN
12416 shutdown(data, 1+1);
12417 #endif /* USE_SHUTDOWN */
12418 close(data);
12419 #endif /* TCPIPLIB */
12420 data = -1;
12421 globaldin = -1;
12422 }
12423 if (!out2screen) {
12424 int x = 0;
12425 debug(F111,"ftp failrecv2 zclose",ftprecv.local,keep);
12426 zclose(ZOFILE);
12427 switch (keep) { /* which is... */
12428 case SET_AUTO: /* AUTO */
12429 if (curtype == FTT_ASC) /* Delete file if TYPE A. */
12430 x = 1;
12431 break;
12432 case SET_OFF: /* DISCARD */
12433 x = 1; /* Delete file, period. */
12434 break;
12435 default: /* KEEP */
12436 break;
12437 }
12438 if (x) {
12439 x = zdelet(ftprecv.local);
12440 debug(F111,"ftp failrecv2 delete incomplete",ftprecv.local,x);
12441 }
12442 }
12443 if (ftprecv.din) {
12444 #ifdef TCPIPLIB
12445 socket_close(ftprecv.din);
12446 #else /* TCPIPLIB */
12447 #ifdef USE_SHUTDOWN
12448 shutdown(ftprecv.din, 1+1);
12449 #endif /* USE_SHUTDOWN */
12450 close(ftprecv.din);
12451 #endif /* TCPIPLIB */
12452 }
12453 signal(SIGINT, ftprecv.oldintr);
12454 ftprecvret = -1;
12455
12456 if (havesigint) {
12457 havesigint = 0;
12458 debug(F100,"FTP failftprecv2 chain to trap()...","",0);
12459 #ifdef OS2
12460 debug(F100,"FTP failftprecv2 PostCtrlCSem()...","",0);
12461 PostCtrlCSem();
12462 #else /* OS2 */
12463 if (ftprecv.oldintr != SIG_IGN)
12464 (*ftprecv.oldintr)(SIGINT);
12465 /* NOTREACHED (I hope!) */
12466 debug(F100,"ftp failftprecv2 return from trap()...","",0);
12467 #endif /* OS2 */
12468 }
12469 }
12470
12471 static VOID
12472 #ifdef CK_ANSIC
doftprecv2(VOID * threadinfo)12473 doftprecv2(VOID * threadinfo)
12474 #else
12475 doftprecv2(threadinfo) VOID * threadinfo;
12476 #endif /* CK_ANSIC */
12477 {
12478 register int c, d;
12479 CK_OFF_T bytes = (CK_OFF_T)0;
12480 int bare_lfs = 0;
12481 int blksize = 0;
12482 ULONG start = 0L, stop;
12483 char * p;
12484 static char * rcvbuf = NULL;
12485 static int rcvbufsiz = 0;
12486 #ifdef CK_URL
12487 char newname[CKMAXPATH+1]; /* For file dialog */
12488 #endif /* CK_URL */
12489 extern int adl_ask;
12490
12491 #ifdef FTP_TIMEOUT
12492 ftp_timed_out = 0;
12493 #endif /* FTP_TIMEOUT */
12494
12495 ftprecv.din = -1;
12496 #ifdef NTSIG
12497 if (threadinfo) { /* Thread local storage... */
12498 TlsSetValue(TlsIndex,threadinfo);
12499 debug(F100, "docmdfile called with threadinfo block","", 0);
12500 } else debug(F100, "docmdfile - threadinfo is NULL", "", 0);
12501 #endif /* NTSIG */
12502 #ifdef CK_LOGIN
12503 #ifdef IKSD
12504 #ifdef NT
12505 if (inserver)
12506 setntcreds();
12507 #endif /* NT */
12508 #endif /* IKSD */
12509 #endif /* CK_LOGIN */
12510
12511 if (ftprecv.recover) { /* Initiate recovery */
12512 x = ftpcmd("REST",ckfstoa(ftprecv.localsize),-1,-1,ftp_vbm);
12513 debug(F111,"ftp reply","REST",x);
12514 if (x == REPLY_CONTINUE) {
12515 ftprecv.lmode = "ab";
12516 rs_len = ftprecv.localsize;
12517 } else {
12518 ftprecv.recover = 0;
12519 }
12520 }
12521 /* IMPORTANT: No FTP commands can come between REST and RETR! */
12522
12523 debug(F111,"ftp recvrequest recover E",ftprecv.remote,ftprecv.recover);
12524
12525 /* Send the command and get reply */
12526 debug(F110,"ftp recvrequest cmd",ftprecv.cmd,0);
12527 debug(F110,"ftp recvrequest remote",ftprecv.remote,0);
12528
12529 if (ftpcmd(ftprecv.cmd,ftprecv.remote,ftprecv.fcs,ftprecv.rcs,ftp_vbm)
12530 != REPLY_PRELIM) {
12531 signal(SIGINT, ftprecv.oldintr); /* Bad reply, fail. */
12532 ftprecvret = -1; /* ftpcode is set by ftpcmd() */
12533 #ifdef NTSIG
12534 ckThreadEnd(threadinfo);
12535 #endif /* NTSIG */
12536 return;
12537 }
12538 ftprecv.din = dataconn("r"); /* Good reply, open data connection */
12539 globaldin = ftprecv.din; /* Global copy of file descriptor */
12540 if (ftprecv.din == -1) { /* Check for failure */
12541 ftpcode = -3; /* Code for no data connection */
12542 ftprecvret = -1;
12543 #ifdef NTSIG
12544 ckThreadEnd(threadinfo);
12545 #endif /* NTSIG */
12546 return;
12547 }
12548 #ifdef CK_URL
12549 /* In K95 GUI put up a file box */
12550 if (haveurl && g_url.pth && adl_ask ) { /* Downloading from a URL */
12551 int x;
12552 char * preface =
12553 "\r\nIncoming file from FTP server...\r\n\
12554 Please confirm output file specification or supply an alternative:";
12555
12556 x = uq_file(preface, /* K95 GUI: Put up file box. */
12557 NULL,
12558 4,
12559 NULL,
12560 ftprecv.local ? ftprecv.local : ftprecv.remote,
12561 newname,
12562 CKMAXPATH+1
12563 );
12564 if (x > 0) {
12565 ftprecv.local = newname; /* Substitute user's file name */
12566 if (x == 2) /* And append if user said to */
12567 ftprecv.lmode = "ab";
12568 }
12569 }
12570 #endif /* CK_URL */
12571 x = 1; /* Output file open OK? */
12572 if (ftprecv.pipename) { /* Command */
12573 x = zxcmd(ZOFILE,ftprecv.pipename);
12574 debug(F111,"ftp recvrequest zxcmd",ftprecv.pipename,x);
12575 } else if (!out2screen) { /* File */
12576 struct filinfo xx;
12577 xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
12578 xx.typ = 0; xx.os_specific = NUL; xx.lblopts = 0;
12579 /* Append or New */
12580 xx.dsp = !strcmp(ftprecv.lmode,"ab") ? XYFZ_A : XYFZ_N;
12581 x = zopeno(ZOFILE,ftprecv.local,NULL,&xx);
12582 debug(F111,"ftp recvrequest zopeno",ftprecv.local,x);
12583 }
12584 if (x < 1) { /* Failure to open output file */
12585 if ((!dpyactive || ftp_deb))
12586 fprintf(stderr, "local(2): %s: %s\n", ftprecv.local, ck_errstr());
12587 ftprecvret = -1;
12588 #ifdef NTSIG
12589 ckThreadEnd(threadinfo);
12590 #endif /* NTSIG */
12591 return;
12592 }
12593 blksize = FTP_BUFSIZ; /* Allocate input buffer */
12594
12595 debug(F101,"ftp recvrequest blksize","",blksize);
12596 debug(F101,"ftp recvrequest rcvbufsiz","",rcvbufsiz);
12597
12598 if (rcvbufsiz < blksize) { /* if necessary */
12599 if (rcvbuf) {
12600 free(rcvbuf);
12601 rcvbuf = NULL;
12602 }
12603 rcvbuf = (char *)malloc((unsigned)blksize);
12604 if (!rcvbuf) {
12605 debug(F100,"ftp get rcvbuf malloc failed","",0);
12606 ftpcode = -2;
12607 #ifdef ENOMEM
12608 errno = ENOMEM;
12609 #endif /* ENOMEM */
12610 if ((!dpyactive || ftp_deb))
12611 perror("malloc");
12612 rcvbufsiz = 0;
12613 ftprecvret = -1;
12614 #ifdef NTSIG
12615 ckThreadEnd(threadinfo);
12616 #endif /* NTSIG */
12617 return;
12618 }
12619 debug(F101,"ftp get rcvbuf malloc ok","",blksize);
12620 rcvbufsiz = blksize;
12621 }
12622 debug(F111,"ftp get rcvbufsiz",ftprecv.local,rcvbufsiz);
12623
12624 ffc = (CK_OFF_T)0; /* Character counter */
12625 cps = oldcps = 0L; /* Thruput */
12626 start = gmstimer(); /* Start time (msecs) */
12627 #ifdef GFTIMER
12628 rftimer(); /* Start time (float) */
12629 #endif /* GFTIMER */
12630
12631 debug(F111,"ftp get type",ftprecv.local,curtype);
12632 debug(F101,"ftp recvrequest ftp_dpl","",ftp_dpl);
12633 switch (curtype) {
12634 case FTT_BIN: /* Binary mode */
12635 case FTT_TEN: /* TENEX mode */
12636 d = 0;
12637 while (1) {
12638 errno = 0;
12639 c = secure_read(ftprecv.din, rcvbuf, rcvbufsiz);
12640 if (cancelfile) {
12641 failftprecv2(threadinfo);
12642 #ifdef NTSIG
12643 ckThreadEnd(threadinfo);
12644 #endif /* NTSIG */
12645 return;
12646 }
12647 if (c < 1)
12648 break;
12649 #ifdef printf /* (What if it isn't?) */
12650 if (out2screen && !ftprecv.pipename) {
12651 int i;
12652 for (i = 0; i < c; i++)
12653 printf("%c",rcvbuf[i]);
12654 } else
12655 #endif /* printf */
12656 {
12657 register int i;
12658 i = 0;
12659 errno = 0;
12660 while (i < c) {
12661 if (zmchout(rcvbuf[i++]) < 0) {
12662 d = i;
12663 break;
12664 }
12665 }
12666 }
12667 bytes += c;
12668 ffc += c;
12669 }
12670 #ifdef FTP_TIMEOUT
12671 if (c == -3) {
12672 debug(F100,"ftp recvrequest timeout","",0);
12673 bytes = (CK_OFF_T)-1;
12674 ftp_timed_out = 1;
12675 ftpcode = -3;
12676 } else
12677 #endif /* FTP_TIMEOUT */
12678 if (c < 0) {
12679 debug(F111,"ftp recvrequest errno",ckitoa(c),errno);
12680 if (c == -1 && errno != EPIPE)
12681 if ((!dpyactive || ftp_deb))
12682 perror("netin");
12683 bytes = (CK_OFF_T)-1;
12684 ftpcode = -4;
12685 }
12686 if (d < c) {
12687 ftpcode = -2;
12688 if ((!dpyactive || ftp_deb)) {
12689 char * p;
12690 p = ftprecv.local ? ftprecv.local : ftprecv.pipename;
12691 if (d < 0)
12692 fprintf(stderr,
12693 "local(3): %s: %s\n", ftprecv.local, ck_errstr());
12694 else
12695 fprintf(stderr,
12696 "%s: short write\n", ftprecv.local);
12697 }
12698 }
12699 break;
12700
12701 case FTT_ASC: /* Text mode */
12702 debug(F101,"ftp recvrequest TYPE A xlate","",ftprecv.xlate);
12703 #ifndef NOCSETS
12704 if (ftprecv.xlate) {
12705 int t;
12706 #ifdef CK_ANSIC
12707 int (*fn)(char);
12708 #else
12709 int (*fn)();
12710 #endif /* CK_ANSIC */
12711 debug(F110,"ftp recvrequest (data)","initxlate",0);
12712 initxlate(ftprecv.rcs,ftprecv.fcs); /* (From,To) */
12713 if (ftprecv.pipename) {
12714 fn = pipeout;
12715 debug(F110,"ftp recvrequest ASCII","pipeout",0);
12716 } else {
12717 fn = out2screen ? scrnout : putfil;
12718 debug(F110,"ftp recvrequest ASCII",
12719 out2screen ? "scrnout" : "putfil",0);
12720 }
12721 while (1) {
12722 /* Get byte from net */
12723 c0 = xgnbyte(FC_UCS2,ftprecv.rcs,netgetc);
12724 if (cancelfile) {
12725 failftprecv2(threadinfo);
12726 #ifdef NTSIG
12727 ckThreadEnd(threadinfo);
12728 #endif /* NTSIG */
12729 return;
12730 }
12731 if (c0 < 0)
12732 break;
12733 /* Second byte from net */
12734 c1 = xgnbyte(FC_UCS2,ftprecv.rcs,netgetc);
12735 if (cancelfile) {
12736 failftprecv2(threadinfo);
12737 #ifdef NTSIG
12738 ckThreadEnd(threadinfo);
12739 #endif /* NTSIG */
12740 return;
12741 }
12742 if (c1 < 0)
12743 break;
12744 #ifdef COMMENT
12745 /* K95: Check whether we need this */
12746 if (fileorder > 0) /* Little Endian */
12747 bytswap(&c0,&c1); /* swap bytes*/
12748 #endif /* COMMENT */
12749
12750 #ifdef OS2
12751 if ( out2screen && /* we're translating to UCS-2 */
12752 !k95stdout && !inserver) /* for the real screen... */
12753 {
12754 union {
12755 USHORT ucs2;
12756 UCHAR bytes[2];
12757 } output;
12758
12759 output.bytes[0] = c1;
12760 output.bytes[1] = c0;
12761
12762 VscrnWrtUCS2StrAtt(VCMD,
12763 &output.ucs2,
12764 1,
12765 wherey[VCMD],
12766 wherex[VCMD],
12767 &colorcmd
12768 );
12769
12770 } else
12771 #endif /* OS2 */
12772 {
12773 if ((x = xpnbyte(c0,TC_UCS2,ftprecv.fcs,fn)) < 0) break;
12774 if ((x = xpnbyte(c1,TC_UCS2,ftprecv.fcs,fn)) < 0) break;
12775 }
12776 }
12777 } else {
12778 #endif /* NOCSETS */
12779 while (1) {
12780 c = secure_getc(ftprecv.din,0);
12781 if (cancelfile
12782 #ifdef FTP_TIMEOUT
12783 || ftp_timed_out
12784 #endif /* FTP_TIMEOUT */
12785 ) {
12786 failftprecv2(threadinfo);
12787 #ifdef NTSIG
12788 ckThreadEnd(threadinfo);
12789 #endif /* NTSIG */
12790 return;
12791 }
12792 if (c < 0 || c == EOF)
12793 break;
12794 #ifdef UNIX
12795 /* Record format conversion for Unix */
12796 /* SKIP THIS FOR WINDOWS! */
12797 if (c == '\n')
12798 bare_lfs++;
12799 while (c == '\r') {
12800 bytes++;
12801 if ((c = secure_getc(ftprecv.din,0)) != '\n' ||
12802 ftprecv.tcrflag) {
12803 if (cancelfile) {
12804 failftprecv2(threadinfo);
12805 #ifdef NTSIG
12806 ckThreadEnd(threadinfo);
12807 #endif /* NTSIG */
12808 return;
12809 }
12810 if (c < 0 || c == EOF)
12811 goto break2;
12812 if (c == '\0') {
12813 bytes++;
12814 goto contin2;
12815 }
12816 }
12817 }
12818 if (c < 0)
12819 break;
12820 #endif /* UNX */
12821
12822 if (out2screen && !ftprecv.pipename)
12823 #ifdef printf
12824 printf("%c",(char)c);
12825 #else
12826 putchar((char)c);
12827 #endif /* printf */
12828 else
12829 if ((d = zmchout(c)) < 0)
12830 break;
12831 bytes++;
12832 ffc++;
12833 contin2:
12834 ;
12835 }
12836 break2:
12837 if (bare_lfs && (!dpyactive || ftp_deb)) {
12838 printf("WARNING! %d bare linefeeds received in ASCII mode\n",
12839 bare_lfs);
12840 printf("File might not have transferred correctly.\n");
12841 }
12842 if (ftprecv.din == -1) {
12843 bytes = (CK_OFF_T)-1;
12844 }
12845 if (c == -2)
12846 bytes = (CK_OFF_T)-1;
12847 break;
12848 #ifndef NOCSETS
12849 }
12850 #endif /* NOCSETS */
12851 }
12852 if (ftprecv.pipename || !out2screen) {
12853 zclose(ZOFILE); /* Close the file */
12854 debug(F111,"doftprecv2 zclose ftpcode",ftprecv.local,ftpcode);
12855 if (ftpcode < 0) { /* If download failed */
12856 int x = 0;
12857 switch (keep) { /* which is... */
12858 case SET_AUTO: /* AUTO */
12859 if (curtype == FTT_ASC) /* Delete file if TYPE A. */
12860 x = 1;
12861 break;
12862 case SET_OFF: /* DISCARD */
12863 x = 1; /* Delete file, period. */
12864 break;
12865 default: /* KEEP */
12866 break;
12867 }
12868 if (x) {
12869 x = zdelet(ftprecv.local);
12870 debug(F111,"ftp get delete incomplete",ftprecv.local,x);
12871 }
12872 }
12873 }
12874 signal(SIGINT, ftprecv.oldintr);
12875 #ifdef SIGPIPE
12876 if (ftprecv.oldintp)
12877 signal(SIGPIPE, ftprecv.oldintp);
12878 #endif /* SIGPIPE */
12879 stop = gmstimer();
12880 #ifdef GFTIMER
12881 fpfsecs = gftimer();
12882 #endif /* GFTIMER */
12883 tfc += ffc;
12884
12885 #ifdef TCPIPLIB
12886 socket_close(ftprecv.din);
12887 #else /* TCPIPLIB */
12888 #ifdef USE_SHUTDOWN
12889 shutdown(ftprecv.din, 1+1);
12890 #endif /* USE_SHUTDOWN */
12891 close(ftprecv.din);
12892 #endif /* TCPIPLIB */
12893 ftprecv.reply = getreply(0,ftprecv.fcs,ftprecv.rcs,ftp_vbm,0);
12894 ftprecvret = ((ftpcode < 0 || ftprecv.reply == REPLY_TRANSIENT ||
12895 ftprecv.reply == REPLY_ERROR) ? -1 : 0);
12896 #ifdef NTSIG
12897 ckThreadEnd(threadinfo);
12898 #endif /* NTSIG */
12899 }
12900
12901 static int
recvrequest(cmd,local,remote,lmode,printnames,recover,pipename,xlate,fcs,rcs)12902 recvrequest(cmd, local, remote, lmode, printnames, recover, pipename,
12903 xlate, fcs, rcs)
12904 char *cmd, *local, *remote, *lmode, *pipename;
12905 int printnames, recover, xlate, fcs, rcs;
12906 {
12907 #ifdef NT
12908 struct _stat stbuf;
12909 #else /* NT */
12910 struct stat stbuf;
12911 #endif /* NT */
12912
12913 #ifdef DEBUG
12914 if (deblog) {
12915 debug(F111,"ftp recvrequest cmd",cmd,recover);
12916 debug(F110,"ftp recvrequest local ",local,0);
12917 debug(F111,"ftp recvrequest remote",remote,ftp_typ);
12918 debug(F110,"ftp recvrequest pipename ",pipename,0);
12919 debug(F101,"ftp recvrequest xlate","",xlate);
12920 debug(F101,"ftp recvrequest fcs","",fcs);
12921 debug(F101,"ftp recvrequest rcs","",rcs);
12922 }
12923 #endif /* DEBUG */
12924
12925 ftprecv.localsize = (CK_OFF_T)0;
12926
12927 if (remfile) { /* See remcfm(), remtxt() */
12928 if (rempipe) {
12929 pipename = remdest;
12930 } else {
12931 local = remdest;
12932 if (remappd) lmode = "ab";
12933 }
12934 }
12935 out2screen = 0;
12936 if (!cmd) cmd = ""; /* Core dump prevention */
12937 if (!remote) remote = "";
12938 if (!lmode) lmode = "";
12939
12940 if (pipename) { /* No recovery for pipes. */
12941 recover = 0;
12942 if (!local)
12943 local = pipename;
12944 } else {
12945 if (!local) /* Output to screen? */
12946 local = "-";
12947 out2screen = !strcmp(local,"-");
12948 }
12949 debug(F101,"ftp recvrequest out2screen","",out2screen);
12950
12951 #ifdef OS2
12952 if ( ftp_xla && out2screen && !k95stdout && !inserver )
12953 fcs = FC_UCS2;
12954 #endif /* OS2 */
12955
12956 if (out2screen) /* No recovery to screen */
12957 recover = 0;
12958 if (!ftp_typ) /* No recovery in text mode */
12959 recover = 0;
12960 ftprecv.is_retr = (strcmp(cmd, "RETR") == 0);
12961
12962 if (!ftprecv.is_retr) /* No recovery except for RETRieve */
12963 recover = 0;
12964
12965 #ifdef COMMENT
12966 if (!out2screen && !pipename && ftprecv.is_retr) { /* To real file */
12967 if (recursive && ckstrchr(local,'/')) {
12968
12969 }
12970 }
12971 #endif /* COMMENT */
12972
12973 ftprecv.localsize = (CK_OFF_T)0; /* Local file size */
12974 rs_len = (CK_OFF_T)0; /* Recovery point */
12975
12976 debug(F101,"ftp recvrequest recover","",recover);
12977 if (recover) { /* Recovering... */
12978 if (stat(local, &stbuf) < 0) { /* Can't stat local file */
12979 debug(F101,"ftp recvrequest recover stat failed","",errno);
12980 recover = 0; /* So cancel recovery */
12981 } else { /* Have local file info */
12982 ftprecv.localsize = stbuf.st_size; /* Get size */
12983 /* Remote file smaller than local */
12984 if (fsize < ftprecv.localsize) {
12985 debug(F101,"ftp recvrequest recover remote smaller","",fsize);
12986 recover = 0; /* Recovery can't work */
12987 } else if (fsize == ftprecv.localsize) { /* Sizes are equal */
12988 debug(F111,"ftp recvrequest recover equal size",
12989 remote,ftprecv.localsize);
12990 return(1);
12991 }
12992 #ifdef COMMENT
12993 /*
12994 The problem here is that the original partial file never got its date
12995 set, either because FTP DATES was OFF, or because the partial file was
12996 downloaded by some other program that doesn't set local file dates, or
12997 because Kermit only sets the file's date when the download was complete
12998 and successful. In all these cases, the local file has a later time
12999 than the remote.
13000 */
13001 if (recover) { /* Remote is bigger */
13002 x = chkmodtime(local,remote,0); /* Check file dates */
13003 debug(F111,"ftp recvrequest chkmodtime",remote,x);
13004 if (x != 1) /* Dates must be equal! */
13005 recover = 0; /* If not, get whole file */
13006 }
13007 #endif /* COMMENT */
13008 }
13009 debug(F111,"ftp recvrequest recover",remote,recover);
13010 }
13011
13012 #ifdef FTP_PROXY
13013 if (proxy && ftprecv.is_retr)
13014 return(proxtrans(cmd, local ? local : remote, remote));
13015 #endif /* FTP_PROXY */
13016
13017 ftprecv.tcrflag = (feol != CR) && ftprecv.is_retr;
13018
13019 ftprecv.reply = 0;
13020 ftprecv.fcs = fcs;
13021 ftprecv.rcs = rcs;
13022 ftprecv.recover = recover;
13023 ftprecv.xlate = xlate;
13024 ftprecv.cmd = cmd;
13025 ftprecv.local = local;
13026 ftprecv.remote = remote;
13027 ftprecv.lmode = lmode;
13028 ftprecv.pipename = pipename;
13029 ftprecv.oldintp = NULL;
13030 ftpcode = 0;
13031
13032 havesigint = 0;
13033 ftprecv.oldintr = signal(SIGINT, cancelrecv);
13034 if (cc_execute(ckjaddr(recvcancel), doftprecv, failftprecv) < 0)
13035 return -1;
13036
13037 #ifdef FTP_TIMEOUT
13038 debug(F111,"ftp recvrequest ftprecvret",remote,ftprecvret);
13039 debug(F111,"ftp recvrequest ftp_timed_out",remote,ftp_timed_out);
13040 if (ftp_timed_out)
13041 ftprecvret = -1;
13042 #endif /* FTP_TIMEOUT */
13043
13044 if (ftprecvret < 0)
13045 return -1;
13046
13047 if (cc_execute(ckjaddr(recvcancel), doftprecv2, failftprecv2) < 0)
13048 return -1;
13049 return ftprecvret;
13050 }
13051
13052 /*
13053 * Need to start a listen on the data channel before we send the command,
13054 * otherwise the server's connect may fail.
13055 */
13056 static int
initconn()13057 initconn() {
13058 register char *p, *a;
13059 int result, tmpno = 0;
13060 int on = 1;
13061 GSOCKNAME_T len;
13062
13063 #ifndef NO_PASSIVE_MODE
13064 int a1,a2,a3,a4,p1,p2;
13065
13066 if (passivemode) {
13067 data = socket(AF_INET, SOCK_STREAM, 0);
13068 globaldin = data;
13069 if (data < 0) {
13070 perror("ftp: socket");
13071 return(-1);
13072 }
13073 if (ftpcmd("PASV",NULL,0,0,ftp_vbm) != REPLY_COMPLETE) {
13074 printf("Passive mode refused\n");
13075 passivemode = 0;
13076 return(initconn());
13077 }
13078 /*
13079 Now we have a string of comma-separated one-byte unsigned integer values,
13080 The first four are the an IP address. The fifth is the MSB of the port
13081 number, the sixth is the LSB. From that we can make a sockaddr_in.
13082 */
13083 if (sscanf(pasv,"%d,%d,%d,%d,%d,%d",&a1,&a2,&a3,&a4,&p1,&p2) != 6) {
13084 printf("Passive mode address scan failure\n");
13085 return(-1);
13086 };
13087 #ifndef NOHTTP
13088 if (tcp_http_proxy) {
13089 #ifdef OS2
13090 char * agent = "Kermit 95"; /* Default user agent */
13091 #else
13092 char * agent = "C-Kermit";
13093 #endif /* OS2 */
13094 register struct hostent *hp = 0;
13095 struct servent *destsp;
13096 char host[512], *p, *q;
13097 #ifdef IP_TOS
13098 #ifdef IPTOS_THROUGHPUT
13099 int tos;
13100 #endif /* IPTOS_THROUGHPUT */
13101 #endif /* IP_TOS */
13102 int s;
13103 #ifdef DEBUG
13104 extern int debtim;
13105 int xdebtim;
13106 xdebtim = debtim;
13107 debtim = 1;
13108 #endif /* DEBUG */
13109
13110 ckmakxmsg(proxyhost,HTTPCPYL,ckuitoa(a1),".",ckuitoa(a2),
13111 ".",ckuitoa(a3),".",ckuitoa(a4),":",ckuitoa((p1<<8)|p2),
13112 NULL,NULL,NULL
13113 );
13114 memset((char *)&hisctladdr, 0, sizeof (hisctladdr));
13115 for (p = tcp_http_proxy, q=host; *p != '\0' && *p != ':'; p++, q++)
13116 *q = *p;
13117 *q = '\0';
13118
13119 hisctladdr.sin_addr.s_addr = inet_addr(host);
13120 if (hisctladdr.sin_addr.s_addr != INADDR_NONE) /* 2010-03-29 */
13121 {
13122 debug(F110,"initconn A",host,0);
13123 hisctladdr.sin_family = AF_INET;
13124 } else {
13125 debug(F110,"initconn B",host,0);
13126 hp = gethostbyname(host);
13127 #ifdef HADDRLIST
13128 hp = ck_copyhostent(hp); /* make safe copy that won't change */
13129 #endif /* HADDRLIST */
13130 if (hp == NULL) {
13131 fprintf(stderr, "ftp: %s: Unknown host\n", host);
13132 ftpcode = -1;
13133 #ifdef DEBUG
13134 debtim = xdebtim;
13135 #endif /* DEBUG */
13136 return(0);
13137 }
13138 hisctladdr.sin_family = hp->h_addrtype;
13139 #ifdef HADDRLIST
13140 memcpy((char *)&hisctladdr.sin_addr, hp->h_addr_list[0],
13141 sizeof(hisctladdr.sin_addr));
13142 #else /* HADDRLIST */
13143 memcpy((char *)&hisctladdr.sin_addr, hp->h_addr,
13144 sizeof(hisctladdr.sin_addr));
13145 #endif /* HADDRLIST */
13146 }
13147 data = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
13148 debug(F101,"initconn socket","",data);
13149 if (data < 0) {
13150 perror("ftp: socket");
13151 ftpcode = -1;
13152 #ifdef DEBUG
13153 debtim = xdebtim;
13154 #endif /* DEBUG */
13155 return(0);
13156 }
13157 if (*p == ':')
13158 p++;
13159 else
13160 p = "http";
13161
13162 destsp = getservbyname(p,"tcp");
13163 if (destsp)
13164 hisctladdr.sin_port = destsp->s_port;
13165 else if (p)
13166 hisctladdr.sin_port = htons(atoi(p));
13167 else
13168 hisctladdr.sin_port = htons(80);
13169 errno = 0;
13170 #ifdef HADDRLIST
13171 debug(F100,"initconn HADDRLIST","",0);
13172 while
13173 #else
13174 debug(F100,"initconn no HADDRLIST","",0);
13175 if
13176 #endif /* HADDRLIST */
13177 (connect(data, (struct sockaddr *)&hisctladdr,
13178 sizeof (hisctladdr)) < 0) {
13179 debug(F101,"initconn connect failed","",errno);
13180 #ifdef HADDRLIST
13181 if (hp && hp->h_addr_list[1]) {
13182 int oerrno = errno;
13183
13184 fprintf(stderr,
13185 "ftp: connect to address %s: ",
13186 inet_ntoa(hisctladdr.sin_addr)
13187 );
13188 errno = oerrno;
13189 perror("ftphookup");
13190 hp->h_addr_list++;
13191 memcpy((char *)&hisctladdr.sin_addr,
13192 hp->h_addr_list[0],
13193 sizeof(hisctladdr.sin_addr));
13194 fprintf(stdout, "Trying %s...\n",
13195 inet_ntoa(hisctladdr.sin_addr));
13196 #ifdef TCPIPLIB
13197 socket_close(data);
13198 #else /* TCPIPLIB */
13199 close(data);
13200 #endif /* TCPIPLIB */
13201 data = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
13202 if (data < 0) {
13203 perror("ftp: socket");
13204 ftpcode = -1;
13205 #ifdef DEBUG
13206 debtim = xdebtim;
13207 #endif /* DEBUG */
13208 return(0);
13209 }
13210 continue;
13211 }
13212 #endif /* HADDRLIST */
13213 perror("ftp: connect");
13214 ftpcode = -1;
13215 goto bad;
13216 }
13217 if (http_connect(data,
13218 tcp_http_proxy_agent ?
13219 tcp_http_proxy_agent :
13220 agent,
13221 NULL,
13222 tcp_http_proxy_user,
13223 tcp_http_proxy_pwd,
13224 0,
13225 proxyhost
13226 ) < 0) {
13227 #ifdef TCPIPLIB
13228 socket_close(data);
13229 #else /* TCPIPLIB */
13230 close(data);
13231 #endif /* TCPIPLIB */
13232 perror("ftp: connect");
13233 ftpcode = -1;
13234 goto bad;
13235 }
13236 } else
13237 #endif /* NOHTTP */
13238 {
13239 data_addr.sin_family = AF_INET;
13240 data_addr.sin_addr.s_addr = htonl((a1<<24)|(a2<<16)|(a3<<8)|a4);
13241 data_addr.sin_port = htons((p1<<8)|p2);
13242
13243 if (connect(data,
13244 (struct sockaddr *)&data_addr,
13245 sizeof(data_addr)) < 0
13246 ) {
13247 perror("ftp: connect");
13248 return(-1);
13249 }
13250 }
13251 debug(F100,"initconn connect ok","",0);
13252 #ifdef IP_TOS
13253 #ifdef IPTOS_THROUGHPUT
13254 on = IPTOS_THROUGHPUT;
13255 if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
13256 perror("ftp: setsockopt TOS (ignored)");
13257 #endif /* IPTOS_THROUGHPUT */
13258 #endif /* IP_TOS */
13259 memcpy(&hisdataaddr,&data_addr,sizeof(struct sockaddr_in));
13260 return(0);
13261 }
13262 #endif /* NO_PASSIVE_MODE */
13263
13264 noport:
13265 memcpy(&data_addr,&myctladdr,sizeof(struct sockaddr_in));
13266 if (sendport)
13267 data_addr.sin_port = 0; /* let system pick one */
13268 if (data != -1) {
13269 #ifdef TCPIPLIB
13270 socket_close(data);
13271 #else /* TCPIPLIB */
13272 #ifdef USE_SHUTDOWN
13273 shutdown(data, 1+1);
13274 #endif /* USE_SHUTDOWN */
13275 close(data);
13276 #endif /* TCPIPLIB */
13277 }
13278 data = socket(AF_INET, SOCK_STREAM, 0);
13279 globaldin = data;
13280 if (data < 0) {
13281 perror("ftp: socket");
13282 if (tmpno)
13283 sendport = 1;
13284 return(-1);
13285 }
13286 if (!sendport) {
13287 if (setsockopt(data,
13288 SOL_SOCKET,
13289 SO_REUSEADDR,
13290 (char *)&on,
13291 sizeof (on)
13292 ) < 0
13293 ) {
13294 perror("ftp: setsockopt (reuse address)");
13295 goto bad;
13296 }
13297 }
13298 if (bind(data, (struct sockaddr *)&data_addr, sizeof (data_addr)) < 0) {
13299 perror("ftp: bind");
13300 goto bad;
13301 }
13302 len = sizeof (data_addr);
13303 if (getsockname(data, (struct sockaddr *)&data_addr, &len) < 0) {
13304 perror("ftp: getsockname");
13305 goto bad;
13306 }
13307 if (listen(data, 1) < 0) {
13308 perror("ftp: listen");
13309 goto bad;
13310 }
13311 if (sendport) {
13312 a = (char *)&data_addr.sin_addr;
13313 p = (char *)&data_addr.sin_port;
13314 ckmakxmsg(ftpcmdbuf,FTP_BUFSIZ,"PORT ",
13315 UC(a[0]),",",UC(a[1]),",", UC(a[2]),",", UC(a[3]),",",
13316 UC(p[0]),",", UC(p[1]));
13317 result = ftpcmd(ftpcmdbuf,NULL,0,0,ftp_vbm);
13318 if (result == REPLY_ERROR && sendport) {
13319 sendport = 0;
13320 tmpno = 1;
13321 goto noport;
13322 }
13323 return(result != REPLY_COMPLETE);
13324 }
13325 if (tmpno)
13326 sendport = 1;
13327 #ifdef IP_TOS
13328 #ifdef IPTOS_THROUGHPUT
13329 on = IPTOS_THROUGHPUT;
13330 if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
13331 perror("ftp: setsockopt TOS (ignored)");
13332 #endif
13333 #endif
13334 return(0);
13335 bad:
13336 #ifdef TCPIPLIB
13337 socket_close(data);
13338 #else /* TCPIPLIB */
13339 #ifdef USE_SHUTDOWN
13340 shutdown(data, 1+1);
13341 #endif /* USE_SHUTDOWN */
13342 close(data);
13343 #endif /* TCPIPLIB */
13344 data = -1;
13345 globaldin = data;
13346 if (tmpno)
13347 sendport = 1;
13348 return(-1);
13349 }
13350
13351 #ifdef CK_SSL
13352 static int
ssl_dataconn()13353 ssl_dataconn() {
13354 if (ssl_ftp_data_con!=NULL) { /* Do SSL */
13355 SSL_free(ssl_ftp_data_con);
13356 ssl_ftp_data_con=NULL;
13357 }
13358 ssl_ftp_data_con=(SSL *)SSL_new(ssl_ftp_ctx);
13359
13360 SSL_set_fd(ssl_ftp_data_con,data);
13361 SSL_set_verify(ssl_ftp_data_con,ssl_verify_flag,NULL);
13362
13363 SSL_copy_session_id(ssl_ftp_data_con,ssl_ftp_con);
13364
13365 if (ssl_debug_flag) {
13366 fprintf(stderr,"=>START SSL connect on DATA\n");
13367 fflush(stderr);
13368 }
13369 if (SSL_connect(ssl_ftp_data_con) <= 0) {
13370 static char errbuf[1024];
13371 ckmakmsg(errbuf,1024,"ftp: SSL_connect DATA error: ",
13372 ERR_error_string(ERR_get_error(),NULL),NULL,NULL);
13373 fprintf(stderr,"%s\n", errbuf);
13374 fflush(stderr);
13375 #ifdef TCPIPLIB
13376 socket_close(data);
13377 #else /* TCPIPLIB */
13378 #ifdef USE_SHUTDOWN
13379 shutdown(data, 1+1);
13380 #endif /* USE_SHUTDOWN */
13381 close(data);
13382 #endif /* TCPIPLIB */
13383 data = -1;
13384 globaldin = data;
13385 return(-1);
13386 } else {
13387 ssl_ftp_data_active_flag=1;
13388
13389 if (!ssl_certsok_flag &&
13390 (ssl_verify_flag & SSL_VERIFY_PEER) && /* JEA 2013-12-10 */
13391 !tls_is_krb5(2)) {
13392 char *subject = ssl_get_subject_name(ssl_ftp_data_con);
13393
13394 if (!subject) {
13395 if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
13396 debug(F110,"dataconn","[SSL _- FAILED]",0);
13397
13398 ssl_ftp_data_active_flag = 0;
13399 #ifdef TCPIPLIB
13400 socket_close(data);
13401 #else /* TCPIPLIB */
13402 #ifdef USE_SHUTDOWN
13403 shutdown(data, 1+1);
13404 #endif /* USE_SHUTDOWN */
13405 close(data);
13406 #endif /* TCPIPLIB */
13407 data = -1;
13408 globaldin = data;
13409 return(-1);
13410 } else {
13411 if (!out2screen && displa && fdispla) {
13412 ftscreen(SCR_TC,0,(CK_OFF_T)0,"Display canceled");
13413 /* fdispla = XYFD_B; */
13414 }
13415
13416 if (uq_ok(
13417 "Warning: Server didn't provide a certificate on data connection\n",
13418 "Continue with file transfer? (Y/N)",
13419 3,NULL,0) <= 0) {
13420 debug(F110, "dataconn","[SSL - FAILED]",0);
13421 ssl_ftp_data_active_flag = 0;
13422 #ifdef TCPIPLIB
13423 socket_close(data);
13424 #else /* TCPIPLIB */
13425 #ifdef USE_SHUTDOWN
13426 shutdown(data, 1+1);
13427 #endif /* USE_SHUTDOWN */
13428 close(data);
13429 #endif /* TCPIPLIB */
13430 data = -1;
13431 globaldin = data;
13432 return(-1);
13433 }
13434 }
13435 } else {
13436 if (!out2screen && displa && fdispla == XYFD_C) {
13437 ftscreen(SCR_TC,0,(CK_OFF_T)0,"Display canceled");
13438 /* fdispla = XYFD_B; */
13439 }
13440
13441 if (ssl_check_server_name(ssl_ftp_data_con,ftp_user_host)) {
13442 debug(F110,"dataconn","[SSL - FAILED]",0);
13443 ssl_ftp_data_active_flag = 0;
13444 #ifdef TCPIPLIB
13445 socket_close(data);
13446 #else /* TCPIPLIB */
13447 #ifdef USE_SHUTDOWN
13448 shutdown(data, 1+1);
13449 #endif /* USE_SHUTDOWN */
13450 close(data);
13451 #endif /* TCPIPLIB */
13452 data = -1;
13453 globaldin = data;
13454 return(-1);
13455 }
13456 }
13457 }
13458 debug(F110,"dataconn","[SSL - OK]",0);
13459 #ifdef COMMENT
13460 /* This messes up the full screen file transfer display */
13461 ssl_display_connect_details(ssl_ftp_con,0,ssl_verbose_flag);
13462 #endif /* COMMENT */
13463 }
13464 if (ssl_debug_flag) {
13465 fprintf(stderr,"=>DONE SSL connect on DATA\n");
13466 fflush(stderr);
13467 }
13468 return(data);
13469 }
13470 #endif /* CK_SSL */
13471
13472 static int
dataconn(lmode)13473 dataconn(lmode) char *lmode; {
13474 int s;
13475 #ifdef IP_TOS
13476 int tos;
13477 #endif /* IP_TOS */
13478 #ifdef UCX50
13479 static u_int fromlen;
13480 #else
13481 static SOCKOPT_T fromlen;
13482 #endif /* UCX50 */
13483
13484 fromlen = sizeof(hisdataaddr);
13485
13486 #ifndef NO_PASSIVE_MODE
13487 if (passivemode) {
13488 #ifdef CK_SSL
13489 ssl_ftp_data_active_flag=0;
13490 if (ssl_ftp_active_flag &&
13491 (ssl_ftp_proxy || ftp_dpl == FPL_PRV))
13492 return(ssl_dataconn());
13493 #endif /* CK_SSL */
13494 return(data);
13495 }
13496 #endif /* NO_PASSIVE_MODE */
13497
13498 s = accept(data, (struct sockaddr *) &hisdataaddr, &fromlen);
13499 if (s < 0) {
13500 perror("ftp: accept");
13501 #ifdef TCPIPLIB
13502 socket_close(data);
13503 #else /* TCPIPLIB */
13504 #ifdef USE_SHUTDOWN
13505 shutdown(data, 1+1);
13506 #endif /* USE_SHUTDOWN */
13507 close(data);
13508 #endif /* TCPIPLIB */
13509 data = -1;
13510 globaldin = data;
13511 return(-1);
13512 }
13513 #ifdef TCPIPLIB
13514 socket_close(data);
13515 #else /* TCPIPLIB */
13516 #ifdef USE_SHUTDOWN
13517 shutdown(data, 1+1);
13518 #endif /* USE_SHUTDOWN */
13519 close(data);
13520 #endif /* TCPIPLIB */
13521 data = s;
13522 globaldin = data;
13523 #ifdef IP_TOS
13524 #ifdef IPTOS_THROUGHPUT
13525 tos = IPTOS_THROUGHPUT;
13526 if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
13527 perror("ftp: setsockopt TOS (ignored)");
13528 #endif /* IPTOS_THROUGHPUT */
13529 #endif /* IP_TOS */
13530
13531 #ifdef CK_SSL
13532 ssl_ftp_data_active_flag=0;
13533 if (ssl_ftp_active_flag &&
13534 (ssl_ftp_proxy || ftp_dpl == FPL_PRV))
13535 return(ssl_dataconn());
13536 #endif /* CK_SSL */
13537 return(data);
13538 }
13539
13540 #ifdef FTP_PROXY
13541 static sigtype
pscancel(sig)13542 pscancel(sig) int sig; {
13543 cancelfile++;
13544 }
13545
13546 static VOID
pswitch(flag)13547 pswitch(flag) int flag; {
13548 extern int proxy;
13549 sig_t oldintr;
13550 static struct comvars {
13551 int connect;
13552 char name[MAXHOSTNAMELEN];
13553 struct sockaddr_in mctl;
13554 struct sockaddr_in hctl;
13555 FILE *in;
13556 FILE *out;
13557 int tpe;
13558 int curtpe;
13559 int cpnd;
13560 int sunqe;
13561 int runqe;
13562 int mcse;
13563 int ntflg;
13564 char nti[17];
13565 char nto[17];
13566 int mapflg;
13567 char mi[CKMAXPATH];
13568 char mo[CKMAXPATH];
13569 char *authtype;
13570 int clvl;
13571 int dlvl;
13572 #ifdef FTP_KRB4
13573 des_cblock session;
13574 des_key_schedule ftp_sched;
13575 #endif /* FTP_KRB4 */
13576 #ifdef FTP_GSSAPI
13577 gss_ctx_id_t gcontext;
13578 #endif /* GSSAPI */
13579 } proxstruct, tmpstruct;
13580 struct comvars *ip, *op;
13581
13582 cancelfile = 0;
13583 oldintr = signal(SIGINT, pscancel);
13584 if (flag) {
13585 if (proxy)
13586 return;
13587 ip = &tmpstruct;
13588 op = &proxstruct;
13589 proxy++;
13590 } else {
13591 if (!proxy)
13592 return;
13593 ip = &proxstruct;
13594 op = &tmpstruct;
13595 proxy = 0;
13596 }
13597 ip->connect = connected;
13598 connected = op->connect;
13599 if (ftp_host) {
13600 strncpy(ip->name, ftp_host, MAXHOSTNAMELEN - 1);
13601 ip->name[MAXHOSTNAMELEN - 1] = '\0';
13602 ip->name[strlen(ip->name)] = '\0';
13603 } else
13604 ip->name[0] = 0;
13605 ftp_host = op->name;
13606 ip->hctl = hisctladdr;
13607 hisctladdr = op->hctl;
13608 ip->mctl = myctladdr;
13609 myctladdr = op->mctl;
13610 ip->in = csocket;
13611 csocket = op->in;
13612 ip->out = csocket;
13613 csocket = op->out;
13614 ip->tpe = ftp_typ;
13615 ftp_typ = op->tpe;
13616 ip->curtpe = curtype;
13617 curtype = op->curtpe;
13618 ip->cpnd = cpend;
13619 cpend = op->cpnd;
13620 ip->sunqe = ftp_usn;
13621 ftp_usn = op->sunqe;
13622 ip->mcse = mcase;
13623 mcase = op->mcse;
13624 ip->ntflg = ntflag;
13625 ntflag = op->ntflg;
13626 strncpy(ip->nti, ntin, 16);
13627 (ip->nti)[strlen(ip->nti)] = '\0';
13628 strcpy(ntin, op->nti);
13629 strncpy(ip->nto, ntout, 16);
13630 (ip->nto)[strlen(ip->nto)] = '\0';
13631 strcpy(ntout, op->nto);
13632 ip->mapflg = mapflag;
13633 mapflag = op->mapflg;
13634 strncpy(ip->mi, mapin, CKMAXPATH - 1);
13635 (ip->mi)[strlen(ip->mi)] = '\0';
13636 strcpy(mapin, op->mi);
13637 strncpy(ip->mo, mapout, CKMAXPATH - 1);
13638 (ip->mo)[strlen(ip->mo)] = '\0';
13639 strcpy(mapout, op->mo);
13640 ip->authtype = auth_type;
13641 auth_type = op->authtype;
13642 ip->clvl = ftp_cpl;
13643 ftp_cpl = op->clvl;
13644 ip->dlvl = ftp_dpl;
13645 ftp_dpl = op->dlvl;
13646 if (!ftp_cpl)
13647 ftp_cpl = FPL_CLR;
13648 if (!ftp_dpl)
13649 ftp_dpl = FPL_CLR;
13650 #ifdef FTP_KRB4
13651 memcpy(ip->session, ftp_cred.session, sizeof(ftp_cred.session));
13652 memcpy(ftp_cred.session, op->session, sizeof(ftp_cred.session));
13653 memcpy(ip->schedule, ftp_sched, sizeof(ftp_sched));
13654 memcpy(ftp_sched, op->schedule, sizeof(ftp_sched));
13655 #endif /* FTP_KRB4 */
13656 #ifdef FTP_GSSAPI
13657 ip->gcontext = gcontext;
13658 gcontext = op->gcontext;
13659 #endif /* GSSAPI */
13660 signal(SIGINT, oldintr);
13661 if (cancelfile) {
13662 cancelfile = 0;
13663 debug(F101,"pswitch cancelfile B","",cancelfile);
13664 (*oldintr)(SIGINT);
13665 }
13666 }
13667
13668 static sigtype
cancelpt(sig)13669 cancelpt(sig) int sig; {
13670 printf("\n");
13671 fflush(stdout);
13672 ptabflg++;
13673 cancelfile = 0;
13674 #ifndef OS2
13675 longjmp(ptcancel, 1);
13676 #else
13677 PostCtrlCSem();
13678 #endif /* OS2 */
13679 }
13680
13681 void
proxtrans(cmd,local,remote,unique)13682 proxtrans(cmd, local, remote, unique) char *cmd, *local, *remote; int unique; {
13683 sig_t oldintr;
13684 int secndflag = 0, prox_type, nfnd;
13685 char *cmd2;
13686 #ifdef BSDSELECT
13687 fd_set mask;
13688 #endif /* BSDSELECT */
13689 sigtype cancelpt();
13690
13691 if (strcmp(cmd, "RETR"))
13692 cmd2 = "RETR";
13693 else
13694 cmd2 = unique ? "STOU" : "STOR";
13695 if ((prox_type = type) == 0) {
13696 if (servertype == SYS_UNIX && unix_proxy)
13697 prox_type = FTT_BIN;
13698 else
13699 prox_type = FTT_ASC;
13700 }
13701 if (curtype != prox_type)
13702 changetype(prox_type, 1);
13703 if (ftpcmd("PASV",NULL,0,0,ftp_vbm) != REPLY_COMPLETE) {
13704 printf("Proxy server does not support third party transfers.\n");
13705 return;
13706 }
13707 pswitch(0);
13708 if (!connected) {
13709 printf("No primary connection\n");
13710 pswitch(1);
13711 ftpcode = -1;
13712 return;
13713 }
13714 if (curtype != prox_type)
13715 changetype(prox_type, 1);
13716
13717 if (ftpcmd("PORT",pasv,-1,-1,ftp_vbm) != REPLY_COMPLETE) {
13718 pswitch(1);
13719 return;
13720 }
13721
13722 /* Replace with calls to cc_execute() */
13723 if (setjmp(ptcancel))
13724 goto cancel;
13725 oldintr = signal(SIGINT, cancelpt);
13726 if (ftpcmd(cmd,remote,-1,-1,ftp_vbm) != PRELIM) {
13727 signal(SIGINT, oldintr);
13728 pswitch(1);
13729 return;
13730 }
13731 sleep(2000);
13732 pswitch(1);
13733 secndflag++;
13734 if (ftpcmd(cmd2,local,-1,-1,ftp_vbm) != PRELIM)
13735 goto cancel;
13736 ptflag++;
13737 getreply(0,-1,-1,ftp_vbm,0);
13738 pswitch(0);
13739 getreply(0,-1,-1,ftp_vbm,0);
13740 signal(SIGINT, oldintr);
13741 pswitch(1);
13742 ptflag = 0;
13743 return;
13744
13745 cancel:
13746 signal(SIGINT, SIG_IGN);
13747 ptflag = 0;
13748 if (strcmp(cmd, "RETR") && !proxy)
13749 pswitch(1);
13750 else if (!strcmp(cmd, "RETR") && proxy)
13751 pswitch(0);
13752 if (!cpend && !secndflag) { /* only here if cmd = "STOR" (proxy=1) */
13753 if (ftpcmd(cmd2,local,-1,-1,ftp_vbm) != PRELIM) {
13754 pswitch(0);
13755 if (cpend)
13756 cancel_remote(0);
13757 }
13758 pswitch(1);
13759 if (ptabflg)
13760 ftpcode = -1;
13761 signal(SIGINT, oldintr);
13762 return;
13763 }
13764 if (cpend)
13765 cancel_remote(0);
13766 pswitch(!proxy);
13767 if (!cpend && !secndflag) { /* only if cmd = "RETR" (proxy=1) */
13768 if (ftpcmd(cmd2,local,-1,-1,ftp_vbm) != PRELIM) {
13769 pswitch(0);
13770 if (cpend)
13771 cancel_remote(0);
13772 pswitch(1);
13773 if (ptabflg)
13774 ftpcode = -1;
13775 signal(SIGINT, oldintr);
13776 return;
13777 }
13778 }
13779 if (cpend)
13780 cancel_remote(0);
13781 pswitch(!proxy);
13782 if (cpend) {
13783 #ifdef BSDSELECT
13784 FD_ZERO(&mask);
13785 FD_SET(csocket, &mask);
13786 if ((nfnd = empty(&mask, 10)) <= 0) {
13787 if (nfnd < 0) {
13788 perror("cancel");
13789 }
13790 if (ptabflg)
13791 ftpcode = -1;
13792 lostpeer();
13793 }
13794 #else /* BSDSELECT */
13795 #ifdef IBMSELECT
13796 if ((nfnd = empty(&csocket, 1, 10)) <= 0) {
13797 if (nfnd < 0) {
13798 perror("cancel");
13799 }
13800 if (ptabflg)
13801 ftpcode = -1;
13802 lostpeer();
13803 }
13804 #endif /* IBMSELECT */
13805 #endif /* BSDSELECT */
13806 getreply(0,-1,-1,ftp_vbm,0);
13807 getreply(0,-1,-1,ftp_vbm,0);
13808 }
13809 if (proxy)
13810 pswitch(0);
13811 pswitch(1);
13812 if (ptabflg)
13813 ftpcode = -1;
13814 signal(SIGINT, oldintr);
13815 }
13816 #endif /* FTP_PROXY */
13817
13818 #ifdef FTP_SECURITY
13819 #ifdef FTP_GSSAPI
13820
13821 #ifdef COMMENT
13822 /* ck_gss_mech_krb5 is not declared anywhere */
13823 struct {
13824 CONST gss_OID_desc * CONST * mech_type;
13825 char *service_name;
13826 } gss_trials[] = {
13827 { &ck_gss_mech_krb5, "ftp" },
13828 { &ck_gss_mech_krb5, "host" },
13829 };
13830 #else
13831 /* This matches what is declared above */
13832 struct {
13833 CONST gss_OID_desc * CONST * mech_type;
13834 char *service_name;
13835 } gss_trials[] = {
13836 { &gss_mech_krb5, "ftp" },
13837 { &gss_mech_krb5, "host" },
13838 };
13839 #endif /* COMMENT */
13840
13841
13842 int n_gss_trials = sizeof(gss_trials)/sizeof(gss_trials[0]);
13843 #endif /* FTP_GSSAPI */
13844
13845 static int
ftp_auth()13846 ftp_auth() {
13847 extern int setsafe();
13848 int j = 0, n;
13849 #ifdef FTP_KRB4
13850 char *service, inst[INST_SZ];
13851 ULONG cksum;
13852 ULONG checksum = (ULONG) getpid();
13853 CHAR out_buf[FTP_BUFSIZ];
13854 int i;
13855 #else /* FTP_KRB4 */
13856 #ifdef FTP_GSSAPI
13857 CHAR out_buf[FTP_BUFSIZ];
13858 int i;
13859 #endif /* FTP_GSSAPI */
13860 #endif /* FTP_KRB4 */
13861
13862 if (ssl_ftp_proxy) /* Do not allow AUTH over SSL proxy */
13863 return(0);
13864
13865 if (auth_type)
13866 return(1); /* auth already succeeded */
13867
13868 /* Try each auth type as specified by the end user */
13869 for (j = 0; j < 8 && ftp_auth_type[j] != 0; j++) {
13870 #ifdef FTP_GSSAPI
13871 if (ftp_auth_type[j] == FTA_GK5 && ck_gssapi_is_installed()) {
13872 n = ftpcmd("AUTH GSSAPI",NULL,0,0,ftp_vbm);
13873 if (n == REPLY_CONTINUE) {
13874 OM_uint32 maj_stat, min_stat;
13875 gss_name_t target_name;
13876 gss_buffer_desc send_tok, recv_tok, *token_ptr;
13877 char stbuf[FTP_BUFSIZ];
13878 int comcode, trial;
13879 struct gss_channel_bindings_struct chan;
13880 char * realm = NULL;
13881 char tgt[256];
13882
13883 chan.initiator_addrtype = GSS_C_AF_INET; /* OM_uint32 */
13884 chan.initiator_address.length = 4;
13885 chan.initiator_address.value = &myctladdr.sin_addr.s_addr;
13886 chan.acceptor_addrtype = GSS_C_AF_INET; /* OM_uint32 */
13887 chan.acceptor_address.length = 4;
13888 chan.acceptor_address.value = &hisctladdr.sin_addr.s_addr;
13889 chan.application_data.length = 0;
13890 chan.application_data.value = 0;
13891
13892 if (!quiet)
13893 printf("GSSAPI accepted as authentication type\n");
13894
13895 realm = ck_krb5_realmofhost(ftp_user_host);
13896 if (realm) {
13897 ckmakmsg(tgt,sizeof(tgt),"krbtgt/",realm,"@",realm);
13898 debug(F110,"ftp_auth(GSSAPI) TGT",tgt,0);
13899 if ( krb5_autoget &&
13900 !((ck_krb5_tkt_isvalid(NULL,tgt) > 0) ||
13901 (ck_krb5_is_tgt_valid() > 0)) )
13902 ck_krb5_autoget_TGT(realm);
13903 }
13904
13905 /* Blob from gss-client */
13906 for (trial = 0; trial < n_gss_trials; trial++) {
13907 /* ftp@hostname first, the host@hostname */
13908 /* the V5 GSSAPI binding canonicalizes this for us... */
13909 ckmakmsg(stbuf,FTP_BUFSIZ,
13910 gss_trials[trial].service_name,
13911 "@",
13912 ftp_user_host,
13913 NULL
13914 );
13915 if (ftp_deb)
13916 fprintf(stderr,
13917 "Authenticating to <%s>...\n", stbuf);
13918 send_tok.value = stbuf;
13919 send_tok.length = strlen(stbuf);
13920 maj_stat = gss_import_name(&min_stat, &send_tok,
13921 gss_nt_service_name,
13922 &target_name
13923 );
13924 if (maj_stat != GSS_S_COMPLETE) {
13925 user_gss_error(maj_stat, min_stat, "parsing name");
13926 secure_error("name parsed <%s>\n", stbuf);
13927 continue;
13928 }
13929 token_ptr = GSS_C_NO_BUFFER;
13930 gcontext = GSS_C_NO_CONTEXT; /* structure copy */
13931
13932 do {
13933 if (ftp_deb)
13934 fprintf(stderr, "calling gss_init_sec_context\n");
13935 maj_stat =
13936 gss_init_sec_context(&min_stat,
13937 GSS_C_NO_CREDENTIAL,
13938 &gcontext,
13939 target_name,
13940 (gss_OID) *
13941 gss_trials[trial].mech_type,
13942 GSS_C_MUTUAL_FLAG |
13943 GSS_C_REPLAY_FLAG |
13944 (ftp_cfw ?
13945 GSS_C_DELEG_FLAG : 0),
13946 0,
13947 /* channel bindings */
13948 (krb5_d_no_addresses ?
13949 GSS_C_NO_CHANNEL_BINDINGS :
13950 &chan),
13951 token_ptr,
13952 NULL, /* ignore mech type */
13953 &send_tok,
13954 NULL, /* ignore ret_flags */
13955 NULL
13956 ); /* ignore time_rec */
13957
13958 if (maj_stat != GSS_S_COMPLETE &&
13959 maj_stat != GSS_S_CONTINUE_NEEDED) {
13960 if (trial == n_gss_trials-1)
13961 user_gss_error(maj_stat,
13962 min_stat,
13963 "initializing context"
13964 );
13965 gss_release_name(&min_stat, &target_name);
13966 /* maybe we missed on the service name */
13967 goto outer_loop;
13968 }
13969 if (send_tok.length != 0) {
13970 int len;
13971 reply_parse = "ADAT="; /* for ftpcmd() later */
13972 len = FTP_BUFSIZ;
13973 kerror =
13974 radix_encode(send_tok.value,
13975 out_buf,
13976 send_tok.length,
13977 &len,
13978 RADIX_ENCODE
13979 );
13980 if (kerror) {
13981 fprintf(stderr,
13982 "Base 64 encoding failed: %s\n",
13983 radix_error(kerror)
13984 );
13985 goto gss_complete_loop;
13986 }
13987 comcode = ftpcmd("ADAT",out_buf,-1,-1,0);
13988 if (comcode != REPLY_COMPLETE
13989 && comcode != REPLY_CONTINUE /* (335) */
13990 ) {
13991 if (trial == n_gss_trials-1) {
13992 fprintf(stderr, "GSSAPI ADAT failed\n");
13993 /* force out of loop */
13994 maj_stat = GSS_S_FAILURE;
13995 }
13996 /*
13997 Backoff to the v1 gssapi is still possible.
13998 Send a new AUTH command. If that fails,
13999 terminate the loop.
14000 */
14001 if (ftpcmd("AUTH GSSAPI",NULL,0,0,ftp_vbm)
14002 != REPLY_CONTINUE) {
14003 fprintf(stderr,
14004 "GSSAPI ADAT failed, AUTH restart failed\n");
14005 /* force out of loop */
14006 maj_stat = GSS_S_FAILURE;
14007 }
14008 goto outer_loop;
14009 }
14010 if (!reply_parse) {
14011 fprintf(stderr,
14012 "No authentication data received from server\n");
14013 if (maj_stat == GSS_S_COMPLETE) {
14014 fprintf(stderr,
14015 "...but no more was needed\n");
14016 goto gss_complete_loop;
14017 } else {
14018 user_gss_error(maj_stat,
14019 min_stat,
14020 "no reply, huh?"
14021 );
14022 goto gss_complete_loop;
14023 }
14024 }
14025 len = FTP_BUFSIZ;
14026 kerror = radix_encode(reply_parse,out_buf,i,&len,
14027 RADIX_DECODE);
14028 if (kerror) {
14029 fprintf(stderr,
14030 "Base 64 decoding failed: %s\n",
14031 radix_error(kerror));
14032 goto gss_complete_loop;
14033 }
14034
14035 /* everything worked */
14036 token_ptr = &recv_tok;
14037 recv_tok.value = out_buf;
14038 recv_tok.length = len;
14039 continue;
14040
14041 /* get out of loop clean */
14042 gss_complete_loop:
14043 trial = n_gss_trials-1;
14044 gss_release_buffer(&min_stat, &send_tok);
14045 gss_release_name(&min_stat, &target_name);
14046 goto outer_loop;
14047 }
14048 } while (maj_stat == GSS_S_CONTINUE_NEEDED);
14049
14050 outer_loop:
14051 if (maj_stat == GSS_S_COMPLETE)
14052 break;
14053 }
14054 if (maj_stat == GSS_S_COMPLETE) {
14055 printf("GSSAPI authentication succeeded\n");
14056 reply_parse = NULL;
14057 auth_type = "GSSAPI";
14058 return(1);
14059 } else {
14060 fprintf(stderr, "GSSAPI authentication failed\n");
14061 reply_parse = NULL;
14062 }
14063 } else {
14064 if (ftp_deb)
14065 fprintf(stderr, "GSSAPI rejected as an authentication type\n");
14066 if (ftpcode == 500 || ftpcode == 502)
14067 return(0);
14068 }
14069 }
14070 #endif /* FTP_GSSAPI */
14071 #ifdef FTP_SRP
14072 if (ftp_auth_type[j] == FTA_SRP && ck_srp_is_installed()) {
14073 if (srp_ftp_auth(ftp_user_host,NULL,NULL))
14074 return(1);
14075 else if (ftpcode == 500 || ftpcode == 502)
14076 return(0);
14077 }
14078 #endif /* FTP_SRP */
14079 #ifdef FTP_KRB4
14080 if (ftp_auth_type[j] == FTA_K4 && ck_krb4_is_installed()) {
14081 n = ftpcmd("AUTH KERBEROS_V4",NULL,0,0,ftp_vbm);
14082 if (n == REPLY_CONTINUE) {
14083 char tgt[4*REALM_SZ+1];
14084 int rc;
14085
14086 if (!quiet)
14087 printf("KERBEROS_V4 accepted as authentication type\n");
14088 ckstrncpy(inst, (char *) krb_get_phost(ftp_user_host),INST_SZ);
14089 ckstrncpy(ftp_realm,
14090 (char *)ck_krb4_realmofhost(ftp_user_host),
14091 REALM_SZ
14092 );
14093
14094 ckmakmsg(tgt,sizeof(tgt),"krbtgt.",ftp_realm,"@",ftp_realm);
14095 rc = ck_krb4_tkt_isvalid(tgt);
14096
14097 if (rc <= 0 && krb4_autoget)
14098 ck_krb4_autoget_TGT(ftp_realm);
14099
14100 service = "ftp";
14101 kerror = krb_mk_req(&ftp_tkt,service,inst,ftp_realm,checksum);
14102 if (kerror == KDC_PR_UNKNOWN) {
14103 service = "rcmd";
14104 kerror = krb_mk_req(&ftp_tkt,
14105 service,
14106 inst,
14107 ftp_realm,
14108 checksum
14109 );
14110 }
14111 if (kerror)
14112 fprintf(stderr, "Kerberos V4 krb_mk_req failed: %s\n",
14113 krb_get_err_text(kerror));
14114 if (!kerror) {
14115 kerror = krb_get_cred(service, inst, ftp_realm,&ftp_cred);
14116 if (kerror)
14117 fprintf(stderr, "Kerberos V4 krb_get_cred failed: %s\n",
14118 krb_get_err_text(kerror));
14119 }
14120 if (!kerror) {
14121 int rc;
14122 rc = des_key_sched(ftp_cred.session, ftp_sched);
14123 if (rc == -1) {
14124 printf("?Invalid DES key specified in credentials\r\n");
14125 debug(F110,"ftp_auth",
14126 "invalid DES Key specified in credentials",0);
14127 } else if ( rc == -2 ) {
14128 printf("?Weak DES key specified in credentials\r\n");
14129 debug(F110,"ftp_auth",
14130 "weak DES Key specified in credentials",0);
14131 } else if ( rc != 0 ) {
14132 printf("?DES Key Schedule not set by credentials\r\n");
14133 debug(F110,"ftp_auth",
14134 "DES Key Schedule not set by credentials",0);
14135 }
14136 reply_parse = "ADAT=";
14137 i = FTP_BUFSIZ;
14138 kerror = radix_encode(ftp_tkt.dat, out_buf, ftp_tkt.length,
14139 &i, RADIX_ENCODE);
14140 if (kerror) {
14141 fprintf(stderr, "Base 64 encoding failed: %s\n",
14142 radix_error(kerror));
14143 goto krb4_err;
14144 }
14145 if (i > FTP_BUFSIZ - 6)
14146 printf("?ADAT data too long\n");
14147 if (ftpcmd("ADAT",out_buf,-1,-1,0) !=
14148 REPLY_COMPLETE) {
14149 fprintf(stderr, "Kerberos V4 authentication failed\n");
14150 goto krb4_err;
14151 }
14152 if (!reply_parse) {
14153 fprintf(stderr,
14154 "No authentication data received from server\n");
14155 goto krb4_err;
14156 }
14157 i = sizeof(out_buf);
14158 kerror =
14159 radix_encode(reply_parse, out_buf, 0, &i, RADIX_DECODE);
14160 if (kerror) {
14161 fprintf(stderr, "Base 64 decoding failed: %s\n",
14162 radix_error(kerror));
14163 goto krb4_err;
14164 }
14165 kerror = krb_rd_safe(out_buf, i,
14166 #ifdef KRB524
14167 ftp_cred.session,
14168 #else /* KRB524 */
14169 &ftp_cred.session,
14170 #endif /* KRB524 */
14171 &hisctladdr,
14172 &myctladdr,
14173 &ftp_msg_data
14174 );
14175 if (kerror) {
14176 fprintf(stderr, "Kerberos V4 krb_rd_safe failed: %s\n",
14177 krb_get_err_text(kerror));
14178 goto krb4_err;
14179 }
14180
14181 /* fetch the (modified) checksum */
14182 memcpy(&cksum, ftp_msg_data.app_data, sizeof(cksum));
14183 if (ntohl(cksum) == checksum + 1) {
14184 if (ftp_vbm)
14185 printf("Kerberos V4 authentication succeeded\n");
14186 reply_parse = NULL;
14187 auth_type = "KERBEROS_V4";
14188 return(1);
14189 } else
14190 fprintf(stderr,
14191 "Kerberos V4 mutual authentication failed\n");
14192 krb4_err:
14193 reply_parse = NULL;
14194 }
14195 } else {
14196 if (ftp_deb)
14197 fprintf(stderr,
14198 "KERBEROS_V4 rejected as an authentication type\n");
14199 if (ftpcode == 500 || ftpcode == 502)
14200 return(0);
14201 }
14202 }
14203 #endif /* FTP_KRB4 */
14204 #ifdef CK_SSL
14205 if (ftp_auth_type[j] == FTA_TLS && ck_ssleay_is_installed()) {
14206 #ifdef FTPHOST
14207 if (!hostcmd) {
14208 ftpcmd("HOST",ftp_user_host,0,0,0);
14209 hostcmd = 1;
14210 }
14211 #endif /* FTPHOST */
14212 n = ftpcmd("AUTH TLS",NULL,0,0,ftp_vbm);
14213 if (n != REPLY_COMPLETE)
14214 n = ftpcmd("AUTH TLS-P",NULL,0,0,ftp_vbm);
14215 if (n == REPLY_COMPLETE) {
14216 if (!quiet)
14217 printf("TLS accepted as authentication type\n");
14218
14219 auth_type = "TLS";
14220 ssl_auth();
14221 if (ssl_ftp_active_flag ) {
14222 ftp_dpl = FPL_CLR;
14223 ftp_cpl = FPL_PRV;
14224 return(1);
14225 } else {
14226 fprintf(stderr,"TLS authentication failed\n");
14227 auth_type = NULL;
14228 #ifdef TCPIPLIB
14229 socket_close(csocket);
14230 #else /* TCPIPLIB */
14231 #ifdef USE_SHUTDOWN
14232 shutdown(csocket, 1+1);
14233 #endif /* USE_SHUTDOWN */
14234 close(csocket);
14235 #endif /* TCPIPLIB */
14236 csocket = -1;
14237 if (ftp_hookup(ftp_user_host,ftp_port,0) == NULL)
14238 return(0);
14239 }
14240 } else {
14241 if (ftp_deb)
14242 fprintf(stderr,"TLS rejected as an authentication type\n");
14243 if (ftpcode == 500 || ftpcode == 502)
14244 return(0);
14245 }
14246 }
14247 if (ftp_auth_type[j] == FTA_SSL && ck_ssleay_is_installed()) {
14248 #ifdef FTPHOST
14249 if (!hostcmd) {
14250 ftpcmd("HOST",ftp_user_host,0,0,0);
14251 hostcmd = 1;
14252 }
14253 #endif /* FTPHOST */
14254 n = ftpcmd("AUTH SSL",NULL,0,0,ftp_vbm);
14255 if (n == REPLY_CONTINUE || n == REPLY_COMPLETE) {
14256 if (!quiet)
14257 printf("SSL accepted as authentication type\n");
14258 auth_type = "SSL";
14259 ssl_auth();
14260 if (ssl_ftp_active_flag) {
14261 ftp_dpl = FPL_PRV;
14262 ftp_cpl = FPL_PRV;
14263 setprotbuf(1<<20);
14264 return(1);
14265 } else {
14266 fprintf(stderr,"SSL authentication failed\n");
14267 auth_type = NULL;
14268 #ifdef TCPIPLIB
14269 socket_close(csocket);
14270 #else /* TCPIPLIB */
14271 #ifdef USE_SHUTDOWN
14272 shutdown(csocket, 1+1);
14273 #endif /* USE_SHUTDOWN */
14274 close(csocket);
14275 #endif /* TCPIPLIB */
14276 csocket = -1;
14277 if (ftp_hookup(ftp_user_host,ftp_port,0) == NULL)
14278 return(0);
14279 }
14280 } else {
14281 if (ftp_deb)
14282 fprintf(stderr, "SSL rejected as an authentication type\n");
14283 if (ftpcode == 500 || ftpcode == 502)
14284 return(0);
14285 }
14286 }
14287 #endif /* CK_SSL */
14288 /* Other auth types go here ... */
14289 } /* for (j;;) */
14290 return(0);
14291 }
14292 #endif /* FTP_SECURITY */
14293
14294 static int
14295 #ifdef CK_ANSIC
setprotbuf(unsigned int size)14296 setprotbuf(unsigned int size)
14297 #else
14298 setprotbuf(size) unsigned int size;
14299 #endif /* CK_ANSIC */
14300 /* setprotbuf */ {
14301 if (ucbuf)
14302 free(ucbuf);
14303 ucbuf = NULL;
14304 ucbufsiz = 0;
14305 actualbuf = size;
14306 while ((ucbuf = (CHAR *)malloc(actualbuf)) == NULL) {
14307 if (actualbuf)
14308 actualbuf /= 2;
14309 else
14310 return(0);
14311 }
14312 ucbufsiz = actualbuf - FUDGE_FACTOR;
14313 debug(F101,"setprotbuf ucbufsiz","",ucbufsiz);
14314 if (ucbufsiz < 128) {
14315 printf("WARNING: tiny ucbufsiz: %d\n",ucbufsiz);
14316 } else if (ucbufsiz < 0) {
14317 printf("ERROR: ucbuf allocation failure\n");
14318 return(-1);
14319 }
14320 maxbuf = actualbuf;
14321 return(1);
14322 }
14323
14324 static int
14325 #ifdef CK_ANSIC
setpbsz(unsigned int size)14326 setpbsz(unsigned int size)
14327 #else
14328 setpbsz(size) unsigned int size;
14329 #endif /* CK_ANSIC */
14330 /* setpbsz */ {
14331 if (!setprotbuf(size)) {
14332 perror("?Error while trying to malloc PROT buffer:");
14333 #ifdef FTP_SRP
14334 srp_reset();
14335 #endif /* FTP_SRP */
14336 ftpclose();
14337 return(-1);
14338 }
14339 reply_parse = "PBSZ=";
14340 ckmakmsg(ftpcmdbuf,FTP_BUFSIZ,"PBSZ ",
14341 #ifdef CK_SSL
14342 ssl_ftp_active_flag ? "0" :
14343 #endif /* CK_SSL */
14344 ckuitoa(actualbuf),NULL,NULL);
14345 if (ftpcmd(ftpcmdbuf,NULL,0,0,0) != REPLY_COMPLETE) {
14346 if (connected) {
14347 printf("?Unable to negotiate PROT buffer size with FTP server\n");
14348 ftpclose();
14349 }
14350 return(-1);
14351 }
14352 if (reply_parse) {
14353 if ((maxbuf = (unsigned int) atol(reply_parse)) > actualbuf)
14354 maxbuf = actualbuf;
14355 } else
14356 maxbuf = actualbuf;
14357 ucbufsiz = maxbuf - FUDGE_FACTOR;
14358 debug(F101,"setpbsz ucbufsiz","",ucbufsiz);
14359 reply_parse = NULL;
14360 return(0);
14361 }
14362
14363 static VOID
cancel_remote(din)14364 cancel_remote(din) int din; {
14365 CHAR buf[FTP_BUFSIZ];
14366 int x, nfnd;
14367 #ifdef BSDSELECT
14368 fd_set mask;
14369 #endif /* BSDSELECT */
14370 #ifdef IBMSELECT
14371 int fds[2], fdcnt = 0;
14372 #endif /* IBMSELECT */
14373 #ifdef DEBUG
14374 extern int debtim;
14375 int xdebtim;
14376 xdebtim = debtim;
14377 debtim = 1;
14378 #endif /* DEBUG */
14379 debug(F100,"ftp cancel_remote entry","",0);
14380 #ifdef CK_SSL
14381 if (ssl_ftp_active_flag) {
14382 /*
14383 * Send Telnet IP, Telnet DM but do so inline and within the
14384 * TLS channel
14385 */
14386 int count, error;
14387
14388 buf[0] = IAC;
14389 buf[1] = TN_IP;
14390 buf[2] = IAC;
14391 buf[3] = TN_DM;
14392 buf[4] = NUL;
14393
14394 count = SSL_write(ssl_ftp_con, buf, 4);
14395 debug(F111,"ftp cancel_remote","SSL_write(IAC IP IAC DM)",count);
14396 error = SSL_get_error(ssl_ftp_con,count);
14397 debug(F111,"ftp cancel_remote","SSL_get_error()",error);
14398 switch (error) {
14399 case SSL_ERROR_NONE:
14400 break;
14401 case SSL_ERROR_WANT_WRITE:
14402 case SSL_ERROR_WANT_READ:
14403 case SSL_ERROR_SYSCALL:
14404 #ifdef NT
14405 {
14406 int gle = GetLastError();
14407 }
14408 #endif /* NT */
14409 case SSL_ERROR_WANT_X509_LOOKUP:
14410 case SSL_ERROR_SSL:
14411 case SSL_ERROR_ZERO_RETURN:
14412 default:
14413 lostpeer();
14414 return;
14415 }
14416 } else
14417 #endif /* CK_SSL */
14418 {
14419 /*
14420 * send IAC in urgent mode instead of DM because 4.3BSD places oob mark
14421 * after urgent byte rather than before as is protocol now.
14422 */
14423 buf[0] = IAC;
14424 buf[1] = TN_IP;
14425 buf[2] = IAC;
14426 buf[3] = NUL;
14427 if ((x = send(csocket, (SENDARG2TYPE)buf, 3, MSG_OOB)) != 3)
14428 perror("cancel");
14429 debug(F101,"ftp cancel_remote send 1","",x);
14430 buf[0] = TN_DM;
14431 x = send(csocket,(SENDARG2TYPE)buf,1,0);
14432 debug(F101,"ftp cancel_remote send 2","",x);
14433 }
14434 x = scommand("ABOR");
14435 debug(F101,"ftp cancel_remote scommand","",x);
14436 #ifdef BSDSELECT
14437 FD_ZERO(&mask);
14438 FD_SET(csocket, &mask);
14439 if (din) {
14440 FD_SET(din, &mask);
14441 }
14442 nfnd = empty(&mask, 10);
14443 debug(F101,"ftp cancel_remote empty","",nfnd);
14444 if ((nfnd) <= 0) {
14445 if (nfnd < 0) {
14446 perror("cancel");
14447 }
14448 #ifdef FTP_PROXY
14449 if (ptabflg)
14450 ftpcode = -1;
14451 #endif /* FTP_PROXY */
14452 lostpeer();
14453 }
14454 debug(F110,"ftp cancel_remote","D",0);
14455 if (din && FD_ISSET(din, &mask)) {
14456 /* Security: No threat associated with this read. */
14457 /* But you can't simply read the TLS data stream */
14458 #ifdef CK_SSL
14459 if (ssl_ftp_data_active_flag) {
14460 int count, error;
14461 while ((count = SSL_read(ssl_ftp_data_con, buf, FTP_BUFSIZ)) > 0)
14462 /* LOOP */ ;
14463 } else
14464 #endif /* CK_SSL */
14465 {
14466 while (recv(din, (SENDARG2TYPE)buf, FTP_BUFSIZ,0) > 0)
14467 /* LOOP */ ;
14468 }
14469 }
14470 debug(F110,"ftp cancel_remote","E",0);
14471 #else /* BSDSELECT */
14472 #ifdef IBMSELECT
14473 fds[0] = csocket;
14474 fdcnt++;
14475 if (din) {
14476 fds[1] = din;
14477 fdcnt++;
14478 }
14479 nfnd = empty(fds, fdcnt, 10);
14480 debug(F101,"ftp cancel_remote empty","",nfnd);
14481 if ((nfnd) <= 0) {
14482 if (nfnd < 0) {
14483 perror("cancel");
14484 }
14485 #ifdef FTP_PROXY
14486 if (ptabflg)
14487 ftpcode = -1;
14488 #endif /* FTP_PROXY */
14489 lostpeer();
14490 }
14491 debug(F110,"ftp cancel_remote","D",0);
14492 if (din && select(&din, 1,0,0,1) ) {
14493 #ifdef CK_SSL
14494 if (ssl_ftp_data_active_flag) {
14495 int count, error;
14496 while ((count = SSL_read(ssl_ftp_data_con, buf, FTP_BUFSIZ)) > 0)
14497 /* LOOP */ ;
14498 } else
14499 #endif /* CK_SSL */
14500 {
14501 while (recv(din, (SENDARG2TYPE)buf, FTP_BUFSIZ,0) > 0)
14502 /* LOOP */ ;
14503 }
14504 }
14505 debug(F110,"ftp cancel_remote","E",0);
14506 #else /* IBMSELECT */
14507 Some form of select is required.
14508 #endif /* IBMSELECT */
14509 #endif /* BSDSELECT */
14510 if (getreply(0,-1,-1,ftp_vbm,0) == REPLY_ERROR && ftpcode == 552) {
14511 debug(F110,"ftp cancel_remote","F",0);
14512 /* 552 needed for NIC style cancel */
14513 getreply(0,-1,-1,ftp_vbm,0);
14514 debug(F110,"ftp cancel_remote","G",0);
14515 }
14516 debug(F110,"ftp cancel_remote","H",0);
14517 getreply(0,-1,-1,ftp_vbm,0);
14518 debug(F110,"ftp cancel_remote","I",0);
14519 #ifdef DEBUG
14520 debtim = xdebtim;
14521 #endif /* DEBUG */
14522 }
14523
14524 static int
fts_dpl(x)14525 fts_dpl(x) int x; {
14526 if (!auth_type
14527 #ifdef OS2
14528 || !ck_crypt_is_installed()
14529 #endif /* OS2 */
14530 ) {
14531 switch ( x ) {
14532 case FPL_PRV:
14533 printf("?Cannot set protection level to PRIVATE\n");
14534 return(0);
14535 case FPL_SAF:
14536 printf("?Cannot set protection level to SAFE\n");
14537 return(0);
14538 }
14539 ftp_dpl = x;
14540 return(1);
14541 }
14542
14543 #ifdef CK_SSL
14544 if (x == FPL_SAF &&
14545 (!strcmp(auth_type,"SSL") || !strcmp(auth_type,"TLS"))) {
14546 printf("Cannot set protection level to safe\n");
14547 return(0);
14548 }
14549 #endif /* CK_SSL */
14550 /* Start with a PBSZ of 1 meg */
14551 if (x != FPL_CLR) {
14552 if (setpbsz(DEFAULT_PBSZ) < 0)
14553 return(0);
14554 }
14555 y = ftpcmd(x == FPL_CLR ? "PROT C" :
14556 (x == FPL_SAF ? "PROT S" : "PROT P"), NULL, 0, 0,ftp_vbm);
14557 if (y == REPLY_COMPLETE) {
14558 ftp_dpl = x;
14559 return(1);
14560 }
14561 return(0);
14562 }
14563
14564 static int
fts_cpl(x)14565 fts_cpl(x) int x; {
14566 if (!auth_type
14567 #ifdef OS2
14568 || !ck_crypt_is_installed()
14569 #endif /* OS2 */
14570 ) {
14571 switch ( x ) {
14572 case FPL_PRV:
14573 printf("?Cannot set protection level to PRIVATE\n");
14574 return(0);
14575 case FPL_SAF:
14576 printf("?Cannot set protection level to SAFE\n");
14577 return(0);
14578 }
14579 ftp_cpl = x;
14580 return(1);
14581 }
14582 if (x == FPL_CLR) {
14583 y = ftpcmd("CCC",NULL,0,0,ftp_vbm);
14584 if (y == REPLY_COMPLETE) {
14585 ftp_cpl = x;
14586 return(1);
14587 }
14588 return(0);
14589 }
14590 ftp_cpl = x;
14591 return(1);
14592 }
14593
14594 #ifdef FTP_GSSAPI
14595 static VOID
user_gss_error(maj_stat,min_stat,s)14596 user_gss_error(maj_stat, min_stat, s)
14597 OM_uint32 maj_stat, min_stat;
14598 char *s;
14599 {
14600 /* a lot of work just to report the error */
14601 OM_uint32 gmaj_stat, gmin_stat, msg_ctx;
14602 gss_buffer_desc msg;
14603 msg_ctx = 0;
14604 while (!msg_ctx) {
14605 gmaj_stat = gss_display_status(&gmin_stat, maj_stat,
14606 GSS_C_GSS_CODE,
14607 GSS_C_NULL_OID,
14608 &msg_ctx,
14609 &msg
14610 );
14611 if ((gmaj_stat == GSS_S_COMPLETE)||
14612 (gmaj_stat == GSS_S_CONTINUE_NEEDED)) {
14613 fprintf(stderr, "GSSAPI error major: %s\n",
14614 (char*)msg.value);
14615 gss_release_buffer(&gmin_stat, &msg);
14616 }
14617 if (gmaj_stat != GSS_S_CONTINUE_NEEDED)
14618 break;
14619 }
14620 msg_ctx = 0;
14621 while (!msg_ctx) {
14622 gmaj_stat = gss_display_status(&gmin_stat, min_stat,
14623 GSS_C_MECH_CODE,
14624 GSS_C_NULL_OID,
14625 &msg_ctx,
14626 &msg
14627 );
14628 if ((gmaj_stat == GSS_S_COMPLETE)||
14629 (gmaj_stat == GSS_S_CONTINUE_NEEDED)) {
14630 fprintf(stderr, "GSSAPI error minor: %s\n", (char*)msg.value);
14631 gss_release_buffer(&gmin_stat, &msg);
14632 }
14633 if (gmaj_stat != GSS_S_CONTINUE_NEEDED)
14634 break;
14635 }
14636 fprintf(stderr, "GSSAPI error: %s\n", s);
14637 }
14638 #endif /* FTP_GSSAPI */
14639
14640 #ifndef NOMHHOST
14641 #ifdef datageneral
14642 #define NOMHHOST
14643 #else
14644 #ifdef HPUX5WINTCP
14645 #define NOMHHOST
14646 #endif /* HPUX5WINTCP */
14647 #endif /* datageneral */
14648 #endif /* NOMHHOST */
14649
14650 #ifdef INADDRX
14651 static struct in_addr inaddrx;
14652 #endif /* INADDRX */
14653
14654 static char *
ftp_hookup(host,port,tls)14655 ftp_hookup(host, port, tls) char * host; int port; int tls; {
14656 register struct hostent *hp = 0;
14657 #ifdef IP_TOS
14658 #ifdef IPTOS_THROUGHPUT
14659 int tos;
14660 #endif /* IPTOS_THROUGHPUT */
14661 #endif /* IP_TOS */
14662 int s;
14663 GSOCKNAME_T len;
14664 static char hostnamebuf[MAXHOSTNAMELEN];
14665 char hostname[MAXHOSTNAMELEN] /* , *p, *q */ ;
14666 int cport;
14667 #ifdef DEBUG
14668 extern int debtim;
14669 int xdebtim;
14670 xdebtim = debtim;
14671 debtim = 1;
14672 #endif /* DEBUG */
14673
14674 debug(F111,"ftp_hookup",host,port);
14675
14676 #ifndef NOHTTP
14677 if (tcp_http_proxy) {
14678 struct servent *destsp;
14679 char *p, *q;
14680
14681 ckmakmsg(proxyhost,HTTPCPYL,host,":",ckuitoa(port),NULL);
14682 for (p = tcp_http_proxy, q = hostname;
14683 *p != '\0' && *p != ':';
14684 p++, q++
14685 )
14686 *q = *p;
14687 *q = '\0';
14688
14689 if (*p == ':')
14690 p++;
14691 else
14692 p = "http";
14693
14694 destsp = getservbyname(p,"tcp");
14695 if (destsp)
14696 cport = ntohs(destsp->s_port);
14697 else if (p) {
14698 cport = atoi(p);
14699 } else
14700 cport = 80;
14701 } else
14702 #endif /* NOHTTP */
14703 {
14704 ckstrncpy(hostname,host,MAXHOSTNAMELEN);
14705 cport = port;
14706 }
14707 memset((char *)&hisctladdr, 0, sizeof (hisctladdr));
14708 hisctladdr.sin_addr.s_addr = inet_addr(host);
14709 if (hisctladdr.sin_addr.s_addr != INADDR_NONE) /* 2010-03-29 */
14710 {
14711 debug(F110,"ftp hookup A",hostname,0);
14712 hisctladdr.sin_family = AF_INET;
14713 ckstrncpy(hostnamebuf, hostname, MAXHOSTNAMELEN);
14714 } else {
14715 debug(F110,"ftp hookup B",hostname,0);
14716 hp = gethostbyname(hostname);
14717 #ifdef HADDRLIST
14718 hp = ck_copyhostent(hp); /* make safe copy that won't change */
14719 #endif /* HADDRLIST */
14720 if (hp == NULL) {
14721 fprintf(stderr, "ftp: %s: Unknown host\n", host);
14722 ftpcode = -1;
14723 #ifdef DEBUG
14724 debtim = xdebtim;
14725 #endif /* DEBUG */
14726 return((char *) 0);
14727 }
14728 hisctladdr.sin_family = hp->h_addrtype;
14729 #ifdef HADDRLIST
14730 memcpy((char *)&hisctladdr.sin_addr, hp->h_addr_list[0],
14731 sizeof(hisctladdr.sin_addr));
14732 #else /* HADDRLIST */
14733 memcpy((char *)&hisctladdr.sin_addr, hp->h_addr,
14734 sizeof(hisctladdr.sin_addr));
14735 #endif /* HADDRLIST */
14736 ckstrncpy(hostnamebuf, hp->h_name, MAXHOSTNAMELEN);
14737 }
14738 debug(F110,"ftp hookup C",hostnamebuf,0);
14739 ftp_host = hostnamebuf;
14740 s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
14741 debug(F101,"ftp hookup socket","",s);
14742 if (s < 0) {
14743 perror("ftp: socket");
14744 ftpcode = -1;
14745 #ifdef DEBUG
14746 debtim = xdebtim;
14747 #endif /* DEBUG */
14748 return(0);
14749 }
14750 hisctladdr.sin_port = htons(cport);
14751 errno = 0;
14752
14753 #ifdef COMMENT
14754 printf("hisctladdr=%d\n",sizeof(hisctladdr));
14755 printf("hisctladdr.sin_addr=%d\n",sizeof(hisctladdr.sin_addr));
14756 printf("sockaddr_in=%d\n",sizeof(struct sockaddr_in));
14757 printf("hisctladdr.sin_addr.s_addr=%d\n",sizeof(hisctladdr.sin_addr.s_addr));
14758 #endif /* COMMENT */
14759
14760 #ifdef HADDRLIST
14761 debug(F100,"ftp hookup HADDRLIST","",0);
14762 while
14763 #else
14764 debug(F100,"ftp hookup no HADDRLIST","",0);
14765 if
14766 #endif /* HADDRLIST */
14767 (connect(s, (struct sockaddr *)&hisctladdr, sizeof (hisctladdr)) < 0) {
14768 debug(F101,"ftp hookup connect failed","",errno);
14769 #ifdef HADDRLIST
14770 if (hp && hp->h_addr_list[1]) {
14771 int oerrno = errno;
14772
14773 fprintf(stderr, "ftp: connect to address %s: ",
14774 inet_ntoa(hisctladdr.sin_addr));
14775 errno = oerrno;
14776 perror((char *) 0);
14777 hp->h_addr_list++;
14778 memcpy((char *)&hisctladdr.sin_addr,
14779 hp->h_addr_list[0],
14780 sizeof(hisctladdr.sin_addr));
14781 fprintf(stdout, "Trying %s...\n",
14782 inet_ntoa(hisctladdr.sin_addr));
14783 #ifdef TCPIPLIB
14784 socket_close(s);
14785 #else /* TCPIPLIB */
14786 close(s);
14787 #endif /* TCPIPLIB */
14788 s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
14789 if (s < 0) {
14790 perror("ftp: socket");
14791 ftpcode = -1;
14792 #ifdef DEBUG
14793 debtim = xdebtim;
14794 #endif /* DEBUG */
14795 return(0);
14796 }
14797 continue;
14798 }
14799 #endif /* HADDRLIST */
14800 perror("ftp: connect");
14801 ftpcode = -1;
14802 goto bad;
14803 }
14804 debug(F100,"ftp hookup connect ok","",0);
14805
14806 len = sizeof (myctladdr);
14807 errno = 0;
14808 if (getsockname(s, (struct sockaddr *)&myctladdr, &len) < 0) {
14809 debug(F101,"ftp hookup getsockname failed","",errno);
14810 perror("ftp: getsockname");
14811 ftpcode = -1;
14812 goto bad;
14813 }
14814 debug(F100,"ftp hookup getsockname ok","",0);
14815
14816 #ifndef NOHTTP
14817 if (tcp_http_proxy) {
14818 #ifdef OS2
14819 char * agent = "Kermit 95"; /* Default user agent */
14820 #else
14821 char * agent = "C-Kermit";
14822 #endif /* OS2 */
14823
14824 if (http_connect(s,agent,NULL,
14825 tcp_http_proxy_user,
14826 tcp_http_proxy_pwd,
14827 0,
14828 proxyhost
14829 ) < 0) {
14830 char * foo = NULL;
14831 #ifdef TCPIPLIB
14832 socket_close(s);
14833 #else /* TCPIPLIB */
14834 close(s);
14835 #endif /* TCPIPLIB */
14836
14837 while (foo == NULL && tcp_http_proxy != NULL ) {
14838
14839 if (tcp_http_proxy_errno == 401 ||
14840 tcp_http_proxy_errno == 407 ) {
14841 char uid[UIDBUFLEN];
14842 char pwd[PWDSIZ];
14843 struct txtbox tb[2];
14844 int ok;
14845
14846 tb[0].t_buf = uid;
14847 tb[0].t_len = UIDBUFLEN;
14848 tb[0].t_lbl = "Proxy Userid: ";
14849 tb[0].t_dflt = NULL;
14850 tb[0].t_echo = 1;
14851 tb[1].t_buf = pwd;
14852 tb[1].t_len = 256;
14853 tb[1].t_lbl = "Proxy Passphrase: ";
14854 tb[1].t_dflt = NULL;
14855 tb[1].t_echo = 2;
14856
14857 ok = uq_mtxt("Proxy Server Authentication Required\n",
14858 NULL, 2, tb);
14859
14860 if (ok && uid[0]) {
14861 char * proxy_user, * proxy_pwd;
14862
14863 proxy_user = tcp_http_proxy_user;
14864 proxy_pwd = tcp_http_proxy_pwd;
14865
14866 tcp_http_proxy_user = uid;
14867 tcp_http_proxy_pwd = pwd;
14868
14869 foo = ftp_hookup(host, port, 0);
14870
14871 debug(F110,"ftp_hookup()",foo,0);
14872 memset(pwd,0,PWDSIZ);
14873 tcp_http_proxy_user = proxy_user;
14874 tcp_http_proxy_pwd = proxy_pwd;
14875 } else
14876 break;
14877 } else
14878 break;
14879 }
14880 if (foo != NULL)
14881 return(foo);
14882 perror("ftp: connect");
14883 ftpcode = -1;
14884 goto bad;
14885 }
14886 ckstrncpy(hostnamebuf, proxyhost, MAXHOSTNAMELEN);
14887 }
14888 #endif /* NOHTTP */
14889
14890 csocket = s;
14891
14892 #ifdef CK_SSL
14893 if (tls) {
14894 /* FTP over SSL
14895 * If the connection is over an SSL proxy then the
14896 * auth_type will be NULL. However, I'm not sure
14897 * whether we should protect the data channel in
14898 * that case or not.
14899 */
14900
14901 debug(F100,"ftp hookup use_tls","",0);
14902 if (!ssl_auth()) {
14903 debug(F100,"ftp hookup ssl_auth failed","",0);
14904 auth_type = NULL;
14905 ftpcode = -1;
14906 csocket = -1;
14907 goto bad;
14908 }
14909 ssl_ftp_proxy = 1;
14910 }
14911 #endif /* CK_SSL */
14912
14913 #ifdef IP_TOS
14914 #ifdef IPTOS_LOWDELAY
14915 tos = IPTOS_LOWDELAY;
14916 if (setsockopt(csocket, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
14917 perror("ftp: setsockopt TOS (ignored)");
14918 #endif
14919 #endif
14920 if (!quiet)
14921 printf("Connected to %s.\n", host);
14922
14923 /* Read greeting from server */
14924 if (getreply(0,ftp_csl,ftp_csr,ftp_vbm,0) > 2) {
14925 debug(F100,"ftp hookup bad reply","",0);
14926 #ifdef TCPIPLIB
14927 socket_close(csocket);
14928 #else /* TCPIPLIB */
14929 close(csocket);
14930 #endif /* TCPIPLIB */
14931 ftpcode = -1;
14932 goto bad;
14933 }
14934 #ifdef SO_OOBINLINE
14935 {
14936 int on = 1;
14937 errno = 0;
14938 if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char *)&on,
14939 sizeof(on)) < 0) {
14940 perror("ftp: setsockopt");
14941 debug(F101,"ftp hookup setsockopt failed","",errno);
14942 }
14943 #ifdef DEBUG
14944 else
14945 debug(F100,"ftp hookup setsockopt ok","",0);
14946 #endif /* DEBUG */
14947 }
14948 #endif /* SO_OOBINLINE */
14949
14950 #ifdef DEBUG
14951 debtim = xdebtim;
14952 #endif /* DEBUG */
14953 return(ftp_host);
14954
14955 bad:
14956 debug(F100,"ftp hookup bad","",0);
14957 #ifdef TCPIPLIB
14958 socket_close(s);
14959 #else /* TCPIPLIB */
14960 close(s);
14961 #endif /* TCPIPLIB */
14962 #ifdef DEBUG
14963 debtim = xdebtim;
14964 #endif /* DEBUG */
14965 csocket = -1;
14966 return((char *)0);
14967 }
14968
14969 static VOID
ftp_init()14970 ftp_init() {
14971 int i, n;
14972
14973 /* The purpose of the initial REST 0 is not clear, but other FTP */
14974 /* clients do it. In any case, failure of this command is not a */
14975 /* reliable indication that the server does not support Restart. */
14976
14977 okrestart = 0;
14978 if (!noinit) {
14979 n = ftpcmd("REST 0",NULL,0,0,0);
14980 if (n == REPLY_COMPLETE)
14981 okrestart = 1;
14982 #ifdef COMMENT
14983 else if (ftp_deb)
14984 printf("WARNING: Unable to restore file pointer.\n");
14985 #endif /* COMMENT */
14986 }
14987 n = ftpcmd("SYST",NULL,0,0,0); /* Get server system type */
14988 if (n == REPLY_COMPLETE) {
14989 register char *cp, c = NUL;
14990 cp = ckstrchr(ftp_reply_str+4,' '); /* Get first word of reply */
14991 if (cp == NULL)
14992 cp = ckstrchr(ftp_reply_str+4,'\r');
14993 if (cp) {
14994 if (cp[-1] == '.')
14995 cp--;
14996 c = *cp; /* Save this char */
14997 *cp = '\0'; /* Replace it with NUL */
14998 }
14999 if (!quiet)
15000 printf("Remote system type is %s.\n",ftp_reply_str+4);
15001 ckstrncpy(ftp_srvtyp,ftp_reply_str+4,SRVNAMLEN);
15002 if (cp) /* Put back saved char */
15003 *cp = c;
15004 }
15005 alike = !ckstrcmp(ftp_srvtyp,myostype,-1,0);
15006
15007 if (!ckstrcmp(ftp_srvtyp,"UNIX",-1,0)) servertype = SYS_UNIX;
15008 else if (!ckstrcmp(ftp_srvtyp,"WIN32",-1,0)) servertype = SYS_WIN32;
15009 else if (!ckstrcmp(ftp_srvtyp,"OS/2",-1,0)) servertype = SYS_WIN32;
15010 else if (!ckstrcmp(ftp_srvtyp,"VMS",-1,0)) servertype = SYS_VMS;
15011 else if (!ckstrcmp(ftp_srvtyp,"DOS",-1,0)) servertype = SYS_DOS;
15012 else if (!ckstrcmp(ftp_srvtyp,"TOPS20",-1,0)) servertype = SYS_TOPS20;
15013 else if (!ckstrcmp(ftp_srvtyp,"TOPS10",-1,0)) servertype = SYS_TOPS10;
15014
15015 #ifdef FTP_PROXY
15016 unix_proxy = 0;
15017 if (servertype == SYS_UNIX && proxy) unix_proxy = 1;
15018 #endif /* FTP_PROXY */
15019
15020 if (ftp_cmdlin && ftp_xfermode == XMODE_M)
15021 ftp_typ = binary; /* Type given on command line */
15022 else /* Otherwise set it automatically */
15023 ftp_typ = alike ? FTT_BIN : FTT_ASC;
15024 changetype(ftp_typ,0); /* Change to this type */
15025 g_ftp_typ = ftp_typ; /* Make it the global type */
15026 if (!quiet)
15027 printf("Default transfer mode is %s\n",
15028 ftp_typ ? "BINARY" : "TEXT (\"ASCII\")"
15029 );
15030 for (i = 0; i < 16; i++) /* Init server FEATure table */
15031 sfttab[i] = 0;
15032 if (!noinit) {
15033 n = ftpcmd("MODE S",NULL,0,0,0); /* We always send in Stream mode */
15034 #ifdef COMMENT
15035 if (n != REPLY_COMPLETE)
15036 printf("WARNING: Server does not accept MODE S(TREAM)\n");
15037 #endif /* COMMENT */
15038 n = ftpcmd("STRU F",NULL,0,0,0); /* STRU File (not Record or Page) */
15039 #ifdef COMMENT
15040 if (n != REPLY_COMPLETE)
15041 printf("WARNING: Server does not accept STRU F(ILE)\n");
15042 #endif /* COMMENT */
15043 if (featok) {
15044 n = ftpcmd("FEAT",NULL,0,0,0); /* Ask server about features */
15045 if (n == REPLY_COMPLETE) {
15046 debug(F101,"ftp_init FEAT","",sfttab[0]);
15047 if (deblog || ftp_deb) {
15048 int i;
15049 for (i = 1; i < 16 && i < nfeattab; i++) {
15050 debug(F111,"ftp_init FEAT",feattab[i].kwd,sfttab[i]);
15051 if (ftp_deb)
15052 printf(" Server %s %s\n",
15053 sfttab[i] ? "supports" : "does not support",
15054 feattab[i].kwd
15055 );
15056 }
15057 /* Deal with disabled MLST opts here if necessary */
15058 /* But why would it be? */
15059 }
15060 }
15061 }
15062 }
15063 }
15064
15065 static int
ftp_login(host)15066 ftp_login(host) char * host; { /* (also called from ckuusy.c) */
15067 static char ftppass[PASSBUFSIZ]="";
15068 char tmp[PASSBUFSIZ];
15069 char *user = NULL, *pass = NULL, *acct = NULL;
15070 int n, aflag = 0;
15071 extern char uidbuf[];
15072 extern char pwbuf[];
15073 extern int pwflg, pwcrypt;
15074
15075 debug(F111,"ftp_login",ftp_logname,ftp_log);
15076
15077 if (!ckstrcmp(ftp_logname,"anonymous",-1,0))
15078 anonymous = 1;
15079 if (!ckstrcmp(ftp_logname,"ftp",-1,0))
15080 anonymous = 1;
15081
15082 #ifdef FTP_SRP
15083 if (auth_type && !strcmp(auth_type, "SRP")) {
15084 user = srp_user;
15085 pass = srp_pass;
15086 acct = srp_acct;
15087 } else
15088 #endif /* FTP_SRP */
15089 if (anonymous) {
15090 user = "anonymous";
15091 if (ftp_tmp) { /* They gave a password */
15092 pass = ftp_tmp;
15093 } else if (ftp_apw) { /* SET FTP ANONYMOUS-PASSWORD */
15094 pass = ftp_apw;
15095 } else { /* Supply user@host */
15096 ckmakmsg(tmp,PASSBUFSIZ,whoami(),"@",myhost,NULL);
15097 pass = tmp;
15098 }
15099 debug(F110,"ftp anonymous",pass,0);
15100 } else {
15101 #ifdef USE_RUSERPASS
15102 if (ruserpass(host, &user, &pass, &acct) < 0) {
15103 ftpcode = -1;
15104 return(0);
15105 }
15106 #endif /* USE_RUSERPASS */
15107 if (ftp_logname) {
15108 user = ftp_logname;
15109 pass = ftp_tmp;
15110 } else if (uidbuf[0] && (ftp_tmp || pwbuf[0] && pwflg)) {
15111 user = uidbuf;
15112 if (ftp_tmp) {
15113 pass = ftp_tmp;
15114 } else if (pwbuf[0] && pwflg) {
15115 ckstrncpy(ftppass,pwbuf,PASSBUFSIZ);
15116 #ifdef OS2
15117 if ( pwcrypt )
15118 ck_encrypt((char *)ftppass);
15119 #endif /* OS2 */
15120 pass = ftppass;
15121 }
15122 }
15123 acct = ftp_acc;
15124 while (user == NULL) {
15125 char *myname, prompt[PROMPTSIZ];
15126 int ok;
15127
15128 myname = whoami();
15129 if (myname)
15130 ckmakxmsg(prompt,PROMPTSIZ," Name (",host,":",myname,"): ",
15131 NULL,NULL,NULL,NULL,NULL,NULL,NULL);
15132 else
15133 ckmakmsg(prompt,PROMPTSIZ," Name (",host,"): ",NULL);
15134 tmp[0] = '\0';
15135
15136 ok = uq_txt(NULL,prompt,1,NULL,tmp,PASSBUFSIZ,NULL,
15137 DEFAULT_UQ_TIMEOUT);
15138 if (!ok || *tmp == '\0')
15139 user = myname;
15140 else
15141 user = brstrip(tmp);
15142 }
15143 }
15144 n = ftpcmd("USER",user,-1,-1,ftp_vbm);
15145 if (n == REPLY_COMPLETE) {
15146 /* determine if we need to send a dummy password */
15147 if (ftpcmd("PWD",NULL,0,0,0) != REPLY_COMPLETE)
15148 ftpcmd("PASS dummy",NULL,0,0,1);
15149 } else if (n == REPLY_CONTINUE) {
15150 #ifdef CK_ENCRYPTION
15151 int oldftp_cpl;
15152 #endif /* CK_ENCRYPTION */
15153
15154 if (pass == NULL) {
15155 int ok;
15156 setint();
15157 ok = uq_txt(NULL," Password: ",2,NULL,ftppass,PASSBUFSIZ,NULL,
15158 DEFAULT_UQ_TIMEOUT);
15159 if (ok)
15160 pass = brstrip(ftppass);
15161 }
15162
15163 #ifdef CK_ENCRYPTION
15164 oldftp_cpl = ftp_cpl;
15165 ftp_cpl = FPL_PRV;
15166 #endif /* CK_ENCRYPTION */
15167 n = ftpcmd("PASS",pass,-1,-1,1);
15168 if (!anonymous && pass) {
15169 char * p = pass;
15170 while (*p++) *(p-1) = NUL;
15171 makestr(&ftp_tmp,NULL);
15172 }
15173 #ifdef CK_ENCRYPTION
15174 /* level may have changed */
15175 if (ftp_cpl == FPL_PRV)
15176 ftp_cpl = oldftp_cpl;
15177 #endif /* CK_ENCRYPTION */
15178 }
15179 if (n == REPLY_CONTINUE) {
15180 aflag++;
15181 if (acct == NULL) {
15182 static char ftpacct[80];
15183 int ok;
15184 setint();
15185 ok = uq_txt(NULL," Account: ",2,NULL,ftpacct,80,NULL,
15186 DEFAULT_UQ_TIMEOUT);
15187 if (ok)
15188 acct = brstrip(ftpacct);
15189 }
15190 n = ftpcmd("ACCT",acct,-1,-1,ftp_vbm);
15191 }
15192 if (n != REPLY_COMPLETE) {
15193 fprintf(stderr, "FTP login failed.\n");
15194 if (haveurl)
15195 doexit(BAD_EXIT,-1);
15196 return(0);
15197 }
15198 if (!aflag && acct != NULL) {
15199 ftpcmd("ACCT",acct,-1,-1,ftp_vbm);
15200 }
15201 makestr(&ftp_logname,user);
15202 loggedin = 1;
15203 #ifdef LOCUS
15204 /* Unprefixed file management commands go to server */
15205 if (autolocus && !ftp_cmdlin) {
15206 setlocus(0,1);
15207 }
15208 #endif /* LOCUS */
15209 ftp_init();
15210
15211 if (anonymous && !quiet) {
15212 printf(" Logged in as anonymous (%s)\n",pass);
15213 memset(pass, 0, strlen(pass));
15214 }
15215 if (ftp_rdir) {
15216 if (doftpcwd(ftp_rdir,-1) < 1)
15217 doexit(BAD_EXIT,-1);
15218 }
15219
15220 #ifdef FTP_PROXY
15221 if (proxy)
15222 return(1);
15223 #endif /* FTP_PROXY */
15224 return(1);
15225 }
15226
15227 static int
ftp_reset()15228 ftp_reset() {
15229 int rc;
15230 #ifdef BSDSELECT
15231 int nfnd = 1;
15232 fd_set mask;
15233 FD_ZERO(&mask);
15234 while (nfnd > 0) {
15235 FD_SET(csocket, &mask);
15236 if ((nfnd = empty(&mask,0)) < 0) {
15237 perror("reset");
15238 ftpcode = -1;
15239 lostpeer();
15240 return(0);
15241 } else if (nfnd) {
15242 getreply(0,-1,-1,ftp_vbm,0);
15243 }
15244 }
15245 #else /* BSDSELECT */
15246 #ifdef IBMSELECT
15247 int nfnd = 1;
15248 while (nfnd > 0) {
15249 if ((nfnd = empty(&csocket,1,0)) < 0) {
15250 perror("reset");
15251 ftpcode = -1;
15252 lostpeer();
15253 return(0);
15254 } else if (nfnd) {
15255 getreply(0,-1,-1,ftp_vbm,0);
15256 }
15257 }
15258 #endif /* IBMSELECT */
15259 #endif /* BSDSELECT */
15260 rc = (ftpcmd("REIN",NULL,0,0,ftp_vbm) == REPLY_COMPLETE);
15261 if (rc > 0)
15262 loggedin = 0;
15263 return(rc);
15264 }
15265
15266 static int
ftp_rename(from,to)15267 ftp_rename(from, to) char * from, * to; {
15268 int lcs = -1, rcs = -1;
15269 #ifndef NOCSETS
15270 if (ftp_xla) {
15271 lcs = ftp_csl;
15272 if (lcs < 0) lcs = fcharset;
15273 rcs = ftp_csx;
15274 if (rcs < 0) rcs = ftp_csr;
15275 }
15276 #endif /* NOCSETS */
15277 if (ftpcmd("RNFR",from,lcs,rcs,ftp_vbm) == REPLY_CONTINUE) {
15278 return(ftpcmd("RNTO",to,lcs,rcs,ftp_vbm) == REPLY_COMPLETE);
15279 }
15280 return(0); /* Failure */
15281 }
15282
15283 static int
ftp_umask(mask)15284 ftp_umask(mask) char * mask; {
15285 int rc;
15286 rc = (ftpcmd("SITE UMASK",mask,-1,-1,1) == REPLY_COMPLETE);
15287 return(rc);
15288 }
15289
15290 static int
ftp_user(user,pass,acct)15291 ftp_user(user,pass,acct) char * user, * pass, * acct; {
15292 int n = 0, aflag = 0;
15293 char pwd[PWDSIZ];
15294
15295 if (!auth_type && ftp_aut) {
15296 #ifdef FTP_SRP
15297 if (ck_srp_is_installed()) {
15298 if (srp_ftp_auth( NULL, user, pass)) {
15299 makestr(&pass,srp_pass);
15300 }
15301 }
15302 #endif /* FTP_SRP */
15303 }
15304 n = ftpcmd("USER",user,-1,-1,ftp_vbm);
15305 if (n == REPLY_COMPLETE)
15306 n = ftpcmd("PASS dummy",NULL,0,0,1);
15307 else if (n == REPLY_CONTINUE) {
15308 #ifdef CK_ENCRYPTION
15309 int oldftp_cpl;
15310 #endif /* CK_ENCRYPTION */
15311 if (pass == NULL || !pass[0]) {
15312 int ok;
15313 pwd[0] = '\0';
15314 setint();
15315 ok = uq_txt(NULL," Password: ",2,NULL,pwd,PWDSIZ,NULL,
15316 DEFAULT_UQ_TIMEOUT);
15317 if (ok)
15318 pass = brstrip(pwd);
15319 }
15320
15321 #ifdef CK_ENCRYPTION
15322 if ((oldftp_cpl = ftp_cpl) == PROT_S)
15323 ftp_cpl = PROT_P;
15324 #endif /* CK_ENCRYPTION */
15325 n = ftpcmd("PASS",pass,-1,-1,1);
15326 memset(pass, 0, strlen(pass));
15327 #ifdef CK_ENCRYPTION
15328 /* level may have changed */
15329 if (ftp_cpl == PROT_P)
15330 ftp_cpl = oldftp_cpl;
15331 #endif /* CK_ENCRYPTION */
15332 }
15333 if (n == REPLY_CONTINUE) {
15334 if (acct == NULL || !acct[0]) {
15335 int ok;
15336 pwd[0] = '\0';
15337 setint();
15338 ok = uq_txt(NULL," Account: ",2,NULL,pwd,PWDSIZ,NULL,
15339 DEFAULT_UQ_TIMEOUT);
15340 if (ok)
15341 acct = pwd;
15342 }
15343 n = ftpcmd("ACCT",acct,-1,-1,ftp_vbm);
15344 aflag++;
15345 }
15346 if (n != REPLY_COMPLETE) {
15347 printf("Login failed.\n");
15348 return(0);
15349 }
15350 if (!aflag && acct != NULL && acct[0]) {
15351 n = ftpcmd("ACCT",acct,-1,-1,ftp_vbm);
15352 }
15353 if (n == REPLY_COMPLETE) {
15354 makestr(&ftp_logname,user);
15355 loggedin = 1;
15356 ftp_init();
15357 return(1);
15358 }
15359 return(0);
15360 }
15361
15362 char *
ftp_authtype()15363 ftp_authtype() {
15364 if (!connected)
15365 return("NULL");
15366 return(auth_type ? auth_type : "NULL");
15367 }
15368
15369 char *
ftp_cpl_mode()15370 ftp_cpl_mode() {
15371 switch (ftp_cpl) {
15372 case FPL_CLR:
15373 return("clear");
15374 case FPL_SAF:
15375 return("safe");
15376 case FPL_PRV:
15377 return("private");
15378 case FPL_CON:
15379 return("confidential");
15380 default:
15381 return("(error)");
15382 }
15383 }
15384
15385 char *
ftp_dpl_mode()15386 ftp_dpl_mode() {
15387 switch (ftp_dpl) {
15388 case FPL_CLR:
15389 return("clear");
15390 case FPL_SAF:
15391 return("safe");
15392 case FPL_PRV:
15393 return("private");
15394 case FPL_CON:
15395 return("confidential");
15396 default:
15397 return("(error)");
15398 }
15399 }
15400
15401
15402 /* remote_files() */
15403 /*
15404 Returns next remote filename on success;
15405 NULL on error or no more files with global rfrc set to:
15406 -1: Bad argument
15407 -2: Server error response to NLST, e.g. file not found
15408 -3: No more files
15409 -9: Internal error
15410 */
15411 #define FTPNAMBUFLEN CKMAXPATH+1024
15412
15413 /* Check: ckmaxfiles CKMAXOPEN */
15414
15415 #define MLSDEPTH 128 /* Stack of open temp files */
15416 static int mlsdepth = 0; /* Temp file stack depth */
15417 static FILE * tmpfilptr[MLSDEPTH+1] = { NULL, NULL }; /* Temp file pointers */
15418 static char * tmpfilnam[MLSDEPTH+1] = { NULL, NULL }; /* Temp file names */
15419
15420 static VOID
mlsreset()15421 mlsreset() { /* Reset MGET temp-file stack */
15422 int i;
15423 for (i = 0; i <= mlsdepth; i++) {
15424 if (tmpfilptr[i]) {
15425 fclose(tmpfilptr[i]);
15426 tmpfilptr[i] = NULL;
15427 if (tmpfilnam[i]) {
15428 #ifdef OS2
15429 unlink(tmpfilnam[i]);
15430 #endif /* OS2 */
15431 free(tmpfilnam[i]);
15432 }
15433 }
15434 }
15435 mlsdepth = 0;
15436 }
15437
15438 static CHAR *
15439 #ifdef CK_ANSIC
remote_files(int new_query,CHAR * arg,CHAR * pattern,int proxy_switch)15440 remote_files(int new_query, CHAR * arg, CHAR * pattern, int proxy_switch)
15441 #else /* CK_ANSIC */
15442 remote_files(new_query, arg, pattern, proxy_switch)
15443 int new_query;
15444 CHAR * arg; /* That we send to the server */
15445 CHAR * pattern; /* That we use locally */
15446 int proxy_switch;
15447 #endif /* CK_ANSIC */
15448 /* remote_files */ {
15449 static CHAR buf[FTPNAMBUFLEN];
15450 CHAR *cp, *whicharg;
15451 char * cdto = NULL;
15452 char * p;
15453 int i, x, forced = 0;
15454 int lcs = 0, rcs = 0, xlate = 0;
15455
15456 debug(F101,"ftp remote_files new_query","",new_query);
15457 debug(F110,"ftp remote_files arg",arg,0);
15458 debug(F110,"ftp remote_files pattern",pattern,0);
15459
15460 rfrc = -1;
15461 if (pattern) /* Treat empty pattern same as NULL */
15462 if (!*pattern)
15463 pattern = NULL;
15464 if (arg) /* Ditto for arg */
15465 if (!*arg)
15466 arg = NULL;
15467
15468 again:
15469
15470 if (new_query) {
15471 if (tmpfilptr[mlsdepth]) {
15472 fclose(tmpfilptr[mlsdepth]);
15473 tmpfilptr[mlsdepth] = NULL;
15474 #ifdef OS2
15475 if (!ftp_deb && !deblog)
15476 unlink(tmpfilnam[mlsdepth]);
15477 #endif /* OS2 */
15478 }
15479 }
15480 if (tmpfilptr[mlsdepth] == NULL) {
15481 extern char * tempdir;
15482 char * p;
15483 debug(F110,"ftp remote_files tempdir",tempdir,0);
15484 if (tempdir) {
15485 p = tempdir;
15486 } else {
15487 #ifdef OS2
15488 #ifdef NT
15489 p = getenv("K95TMP");
15490 #else
15491 p = getenv("K2TMP");
15492 #endif /* NT */
15493 if (!p)
15494 #endif /* OS2 */
15495 p = getenv("CK_TMP");
15496 if (!p)
15497 p = getenv("TMPDIR");
15498 if (!p) p = getenv("TEMP");
15499 if (!p) p = getenv("TMP");
15500 #ifdef OS2ORUNIX
15501 if (p) {
15502 int len = strlen(p);
15503 if (p[len-1] != '/'
15504 #ifdef OS2
15505 && p[len-1] != '\\'
15506 #endif /* OS2 */
15507 ) {
15508 static char foo[CKMAXPATH];
15509 ckstrncpy(foo,p,CKMAXPATH);
15510 ckstrncat(foo,"/",CKMAXPATH);
15511 p = foo;
15512 }
15513 } else
15514 #else /* OS2ORUNIX */
15515 if (!p)
15516 #endif /* OS2ORUNIX */
15517 #ifdef UNIX /* Systems that have a standard */
15518 p = "/tmp/"; /* temporary directory... */
15519 #else
15520 #ifdef datageneral
15521 p = ":TMP:";
15522 #else
15523 p = "";
15524 #endif /* datageneral */
15525 #endif /* UNIX */
15526 }
15527 debug(F110,"ftp remote_files p",p,0);
15528
15529 /* Get temp file */
15530
15531 if ((tmpfilnam[mlsdepth] = (char *)malloc(CKMAXPATH+1))) {
15532 ckmakmsg((char *)tmpfilnam[mlsdepth],
15533 CKMAXPATH+1,p,"ckXXXXXX",NULL,NULL);
15534 } else {
15535 printf("?Malloc failure: remote_files()\n");
15536 return(NULL);
15537 }
15538
15539 #ifdef NT
15540 {
15541 char * tmpfil = mktemp((char *)tmpfilnam[mlsdepth]);
15542 if ( tmpfil )
15543 ckstrncpy(tmpfilnam[mlsdepth],tmpfil,CKMAXPATH+1);
15544 }
15545 #else /* NT */
15546 #ifdef MKTEMP
15547 #ifdef MKSTEMP
15548 x = mkstemp((char *)tmpfilnam[mlsdepth]);
15549 if (x > -1) close(x); /* We just want the name. */
15550 #else
15551 mktemp((char *)tmpfilnam[mlsdepth]);
15552 #endif /* MKSTEMP */
15553 /* if no mktmpnam() the name will just be "ckXXXXXX"... */
15554 #endif /* MKTEMP */
15555 #endif /* NT */
15556
15557 debug(F111,"ftp remote_files tmpfilnam[mlsdepth]",
15558 tmpfilnam[mlsdepth],mlsdepth);
15559
15560 #ifdef FTP_PROXY
15561 if (proxy_switch) {
15562 pswitch(!proxy);
15563 }
15564 #endif /* FTP_PROXY */
15565
15566 debug(F101,"ftp remote_files ftp_xla","",ftp_xla);
15567 debug(F101,"ftp remote_files ftp_csl","",ftp_csl);
15568 debug(F101,"ftp remote_files ftp_csr","",ftp_csr);
15569
15570 #ifndef NOCSETS
15571 xlate = ftp_xla; /* SET FTP CHARACTER-SET-TRANSLATION */
15572 if (xlate) { /* ON? */
15573 lcs = ftp_csl; /* Local charset */
15574 if (lcs < 0) lcs = fcharset;
15575 if (lcs < 0) xlate = 0;
15576 }
15577 if (xlate) { /* Still ON? */
15578 rcs = ftp_csx; /* Remote (Server) charset */
15579 if (rcs < 0) rcs = ftp_csr;
15580 if (rcs < 0) xlate = 0;
15581 }
15582 #endif /* NOCSETS */
15583
15584 forced = mgetforced; /* MGET method forced? */
15585 if (!forced || !mgetmethod) /* Not forced... */
15586 mgetmethod = (sfttab[0] && sfttab[SFT_MLST]) ? /* so pick one */
15587 SND_MLS :
15588 SND_NLS;
15589 /*
15590 User's Command: Result:
15591 mget /nlst NLST (NULL)
15592 mget /nlst foo NLST foo
15593 mget /nlst *.txt NLST *.txt
15594 mget /nlst /match:*.txt NLST (NULL)
15595 mget /nlst /match:*.txt foo NLST foo
15596 mget /mlsd MLSD (NULL)
15597 mget /mlsd foo MLSD foo
15598 mget /mlsd *.txt MLSD (NULL)
15599 mget /mlsd /match:*.txt MLSD (NULL)
15600 mget /mlsd /match:*.txt foo MLSD foo
15601 */
15602 x = -1;
15603 while (x < 0) {
15604 if (pattern) { /* Don't simplify this! */
15605 whicharg = arg;
15606 } else if (mgetmethod == SND_MLS) {
15607 if (arg)
15608 whicharg = iswild((char *)arg) ? NULL : arg;
15609 else
15610 whicharg = NULL;
15611 } else {
15612 whicharg = arg;
15613 }
15614 debug(F110,"ftp remote_files mgetmethod",
15615 mgetmethod == SND_MLS ? "MLSD" : "NLST", 0);
15616 debug(F110,"ftp remote_files whicharg",whicharg,0);
15617
15618 x = recvrequest((mgetmethod == SND_MLS) ? "MLSD" : "NLST",
15619 (char *)tmpfilnam[mlsdepth],
15620 (char *)whicharg,
15621 "wb",
15622 0,
15623 0,
15624 NULL,
15625 xlate,
15626 lcs,
15627 rcs
15628 );
15629 if (x < 0) { /* Chosen method wasn't accepted */
15630 if (forced) {
15631 if (ftpcode > 500 && ftpcode < 505 && !quiet)
15632 printf("?%s: Not supported by server\n",
15633 mgetmethod == SND_MLS ? "MLSD" : "NLST"
15634 );
15635 rfrc = -2; /* Fail */
15636 return(NULL);
15637 }
15638 /* Not forced - if MLSD failed, try NLST */
15639 if (mgetmethod == SND_MLS) { /* Server lied about MLST */
15640 sfttab[SFT_MLST] = 0; /* So disable it */
15641 mlstok = 0; /* and */
15642 mgetmethod = SND_NLS; /* try NLST */
15643 continue;
15644 }
15645 rfrc = -2;
15646 return(NULL);
15647 }
15648 }
15649 #ifdef FTP_PROXY
15650 if (proxy_switch) {
15651 pswitch(!proxy);
15652 }
15653 #endif /* FTP_PROXY */
15654 tmpfilptr[mlsdepth] = fopen((char *)tmpfilnam[mlsdepth], "r");
15655 #ifndef OS2
15656 if (tmpfilptr[mlsdepth]) {
15657 if (!ftp_deb && !deblog)
15658 unlink(tmpfilnam[mlsdepth]);
15659 }
15660 #endif /* OS2 */
15661 notemp:
15662 if (!tmpfilptr[mlsdepth]) {
15663 debug(F110,"ftp remote_files open fail",tmpfilnam[mlsdepth],0);
15664 if ((!dpyactive || ftp_deb))
15665 printf("?Can't find list of remote files, oops\n");
15666 rfrc = -9;
15667 return(NULL);
15668 }
15669 if (ftp_deb)
15670 printf("LISTFILE: %s\n",tmpfilnam[mlsdepth]);
15671 }
15672 buf[0] = NUL;
15673 buf[FTPNAMBUFLEN-1] = NUL;
15674 buf[FTPNAMBUFLEN-2] = NUL;
15675
15676 /* We have to redo all this because the first time was only for */
15677 /* for getting the file list, now it's for getting each file */
15678
15679 if (arg && mgetmethod == SND_MLS) { /* MLSD */
15680 if (!pattern && iswild((char *)arg)) {
15681 pattern = arg; /* Wild arg is really a pattern */
15682 if (pattern)
15683 if (!*pattern)
15684 pattern = NULL;
15685 arg = NULL; /* and not an arg */
15686 }
15687 if (new_query) { /* Initial query? */
15688 cdto = (char *)arg; /* (nonwild) arg given? */
15689 if (cdto)
15690 if (!*cdto)
15691 cdto = NULL;
15692 if (cdto) /* If so, then CD to it */
15693 doftpcwd(cdto,0);
15694 }
15695 }
15696 new_query = 0;
15697
15698 if (fgets((char *)buf, FTPNAMBUFLEN, tmpfilptr[mlsdepth]) == NULL) {
15699 fclose(tmpfilptr[mlsdepth]);
15700 tmpfilptr[mlsdepth] = NULL;
15701
15702 #ifdef OS2
15703 if (!ftp_deb && !deblog)
15704 unlink(tmpfilnam[mlsdepth]);
15705 #endif /* OS2 */
15706 if (ftp_deb && !deblog) {
15707 printf("(Temporary file %s NOT deleted)\n",
15708 (char *)tmpfilnam[mlsdepth]);
15709 }
15710 if (mlsdepth <= 0) { /* EOF at depth 0 */
15711 rfrc = -3; /* means we're done */
15712 return(NULL);
15713 }
15714 printf("POPPING(%d)...\n",mlsdepth-1);
15715 if (tmpfilnam[mlsdepth]) free(tmpfilnam[mlsdepth]);
15716 mlsdepth--;
15717 doftpcdup();
15718 zchdir(".."); /* <-- Not portable */
15719 goto again;
15720 }
15721 if (buf[FTPNAMBUFLEN-1]) {
15722 printf("?BUFFER OVERFLOW -- FTP NLST or MLSD string longer than %d\n",
15723 FTPNAMBUFLEN
15724 );
15725 debug(F101,"remote_files buffer overrun","",FTPNAMBUFLEN);
15726 return(NULL);
15727 }
15728 /* debug(F110,"ftp remote_files buf 1",buf,0); */
15729 if ((cp = (CHAR *)ckstrchr((char *)buf,'\n')) != NULL)
15730 *cp = '\0';
15731 if ((cp = (CHAR *)ckstrchr((char *)buf,'\r')) != NULL)
15732 *cp = '\0';
15733 debug(F110,"ftp remote_files buf",buf,0);
15734 rfrc = 0;
15735
15736 if (ftp_deb)
15737 printf("[%s]\n",(char *)buf);
15738
15739 havesize = (CK_OFF_T)-1; /* Initialize file facts... */
15740 havetype = 0;
15741 makestr(&havemdtm,NULL);
15742 p = (char *)buf;
15743
15744 if (mgetmethod == SND_NLS) { /* NLST... */
15745 if (pattern) {
15746 if (!ckmatch((char *)pattern,p,(servertype == SYS_UNIX),1))
15747 goto again;
15748 }
15749 } else { /* MLSD... */
15750 p = parsefacts((char *)buf);
15751 switch (havetype) {
15752 case FTYP_FILE: /* File: Get it if it matches */
15753 if (pattern) {
15754 if (!ckmatch((char *)pattern,p,(servertype == SYS_UNIX),1))
15755 goto again;
15756 }
15757 break;
15758 case FTYP_CDIR: /* Current directory */
15759 case FTYP_PDIR: /* Parent directory */
15760 goto again; /* Skip */
15761 case FTYP_DIR: /* (Sub)Directory */
15762 if (!recursive) /* If not /RECURSIVE */
15763 goto again; /* Skip */
15764 if (mlsdepth < MLSDEPTH) {
15765 char * p2 = NULL;
15766 mlsdepth++;
15767 printf("RECURSING [%s](%d)...\n",p,mlsdepth);
15768 if (doftpcwd(p,0) > 0) {
15769 int x;
15770 if (!ckstrchr(p,'/')) {
15771 /* zmkdir() needs dirsep */
15772 if ((p2 = (char *)malloc((int)strlen(p) + 2))) {
15773 strcpy(p2,p); /* SAFE */
15774 strcat(p2,"/"); /* SAFE */
15775 p = p2;
15776 }
15777 }
15778 #ifdef NOMKDIR
15779 x = -1;
15780 #else
15781 x = zmkdir(p);
15782 #endif /* NOMKDIR */
15783 if (x > -1) {
15784 zchdir(p);
15785 p = (char *)remote_files(1,arg,pattern,0);
15786 if (p2) free(p2);
15787 } else {
15788 printf("?mkdir failed: [%s] Depth=%d\n",
15789 p,
15790 mlsdepth
15791 );
15792 mlsreset();
15793 if (p2) free(p2);
15794 return(NULL);
15795 }
15796 } else {
15797 printf("?CWD failed: [%s] Depth=%d\n",p,mlsdepth);
15798 mlsreset();
15799 return(NULL);
15800 }
15801 } else {
15802 printf("MAX DIRECTORY STACK DEPTH EXCEEDED: %d\n",
15803 mlsdepth
15804 );
15805 mlsreset();
15806 return(NULL);
15807 }
15808 }
15809 }
15810
15811 #ifdef DEBUG
15812 if (deblog) {
15813 debug(F101,"remote_files havesize","",havesize);
15814 debug(F101,"remote_files havetype","",havetype);
15815 debug(F110,"remote_files havemdtm",havemdtm,0);
15816 debug(F110,"remote_files name",p,0);
15817 }
15818 #endif /* DEBUG */
15819 return((CHAR *)p);
15820 }
15821
15822 /* N O T P O R T A B L E !!! */
15823
15824 #if (SIZEOF_SHORT == 4)
15825 typedef unsigned short ftp_uint32;
15826 typedef short ftp_int32;
15827 #else
15828 #if (SIZEOF_INT == 4)
15829 typedef unsigned int ftp_uint32;
15830 typedef int ftp_int32;
15831 #else
15832 #if (SIZEOF_LONG == 4)
15833 typedef ULONG ftp_uint32;
15834 typedef long ftp_int32;
15835 #endif
15836 #endif
15837 #endif
15838
15839 /* Perhaps use these in general, certainly use them for GSSAPI */
15840
15841 #ifndef looping_write
15842 #define ftp_int32 int
15843 #define ftp_uint32 unsigned int
15844 static int
looping_write(fd,buf,len)15845 looping_write(fd, buf, len)
15846 int fd;
15847 register CONST char *buf;
15848 int len;
15849 {
15850 int cc;
15851 register int wrlen = len;
15852 do {
15853 cc = send(fd, (SENDARG2TYPE)buf, wrlen, 0);
15854 if (cc < 0) {
15855 if (errno == EINTR)
15856 continue;
15857 return(cc);
15858 } else {
15859 buf += cc;
15860 wrlen -= cc;
15861 }
15862 } while (wrlen > 0);
15863 return(len);
15864 }
15865 #endif
15866 #ifndef looping_read
15867 static int
looping_read(fd,buf,len)15868 looping_read(fd, buf, len)
15869 int fd;
15870 register char *buf;
15871 register int len;
15872 {
15873 int cc, len2 = 0;
15874
15875 do {
15876 cc = recv(fd, (char *)buf, len,0);
15877 if (cc < 0) {
15878 if (errno == EINTR)
15879 continue;
15880 return(cc); /* errno is already set */
15881 } else if (cc == 0) {
15882 return(len2);
15883 } else {
15884 buf += cc;
15885 len2 += cc;
15886 len -= cc;
15887 }
15888 } while (len > 0);
15889 return(len2);
15890 }
15891 #endif /* looping_read */
15892
15893 #define ERR -2
15894
15895 #ifdef COMMENT
15896 static
secure_putbyte(fd,c)15897 secure_putbyte(fd, c) int fd; CHAR c; {
15898 int ret;
15899
15900 ucbuf[nout++] = c;
15901 if (nout == (maxbuf ? maxbuf : actualbuf) - FUDGE_FACTOR) {
15902 nout = 0;
15903 if (!ftpissecure())
15904 ret = send(fd, (SENDARG2TYPE)ucbuf,
15905 (maxbuf ? maxbuf : actualbuf) - FUDGE_FACTOR, 0);
15906 else
15907 ret = secure_putbuf(fd,
15908 ucbuf,
15909 (maxbuf ? maxbuf : actualbuf) - FUDGE_FACTOR
15910 );
15911 return(ret?ret:c);
15912 }
15913 return(c);
15914 }
15915 #endif /* COMMENT */
15916
15917 /* returns:
15918 * 0 on success
15919 * -1 on error (errno set)
15920 * -2 on security error
15921 */
15922 static int
secure_flush(fd)15923 secure_flush(fd) int fd; {
15924 int rc = 0;
15925 int len = 0;
15926
15927 if (nout > 0) {
15928 len = nout;
15929 if (!ftpissecure()) {
15930 rc = send(fd, (SENDARG2TYPE)ucbuf, nout, 0);
15931 nout = 0;
15932 goto xflush;
15933 } else {
15934 rc = secure_putbuf(fd, ucbuf, nout);
15935 if (rc)
15936 goto xflush;
15937 }
15938 }
15939 rc = (!ftpissecure()) ? 0 : secure_putbuf(fd, (CHAR *)"", nout = 0);
15940
15941 xflush:
15942 if (rc > -1 && len > 0 && fdispla != XYFD_B) {
15943 spackets++;
15944 spktl = len;
15945 ftscreen(SCR_PT,'D',(CK_OFF_T)spackets,NULL);
15946 }
15947 return(rc);
15948 }
15949
15950 #ifdef COMMENT /* (not used) */
15951 /* returns:
15952 * c>=0 on success
15953 * -1 on error
15954 * -2 on security error
15955 */
15956 static int
15957 #ifdef CK_ANSIC
secure_putc(char c,int fd)15958 secure_putc(char c, int fd)
15959 #else
15960 secure_putc(c, fd) char c; int fd;
15961 #endif /* CK_ANSIC */
15962 /* secure_putc */ {
15963 return(secure_putbyte(fd, (CHAR) c));
15964 }
15965 #endif /* COMMENT */
15966
15967 /* returns:
15968 * nbyte on success
15969 * -1 on error (errno set)
15970 * -2 on security error
15971 */
15972 static int
15973 #ifdef CK_ANSIC
secure_write(int fd,CHAR * buf,unsigned int nbyte)15974 secure_write(int fd, CHAR * buf, unsigned int nbyte)
15975 #else
15976 secure_write(fd, buf, nbyte)
15977 int fd;
15978 CHAR * buf;
15979 unsigned int nbyte;
15980 #endif /* CK_ANSIC */
15981 {
15982 int ret;
15983
15984 #ifdef FTP_TIMEOUT
15985 ftp_timed_out = 0;
15986 if (check_data_connection(fd,1) < 0) {
15987 ftp_timed_out = 1;
15988 return(-3);
15989 }
15990 #endif /* FTP_TIMEOUT */
15991
15992 if (!ftpissecure()) {
15993 if (nout > 0) {
15994 if ((ret = send(fd, (SENDARG2TYPE)ucbuf, nout, 0)) < 0)
15995 return(ret);
15996 nout = 0;
15997 }
15998 return(send(fd,(SENDARG2TYPE)buf,nbyte,0));
15999 } else {
16000 int ucbuflen = (maxbuf ? maxbuf : actualbuf) - FUDGE_FACTOR;
16001 int bsent = 0;
16002
16003 while (bsent < nbyte) {
16004 int b2cp = ((nbyte - bsent) > (ucbuflen - nout) ?
16005 (ucbuflen - nout) : (nbyte - bsent));
16006 #ifdef DEBUG
16007 if (deblog) {
16008 debug(F101,"secure_write ucbuflen","",ucbuflen);
16009 debug(F101,"secure_write ucbufsiz","",ucbufsiz);
16010 debug(F101,"secure_write bsent","",bsent);
16011 debug(F101,"secure_write b2cp","",b2cp);
16012 }
16013 #endif /* DEBUG */
16014 memcpy(&ucbuf[nout],&buf[bsent],b2cp);
16015 nout += b2cp;
16016 bsent += b2cp;
16017
16018 if (nout == ucbuflen) {
16019 nout = 0;
16020 ret = secure_putbuf(fd, ucbuf, ucbuflen);
16021 if (ret < 0)
16022 return(ret);
16023 }
16024 }
16025 return(bsent);
16026 }
16027 }
16028
16029 /* returns:
16030 * 0 on success
16031 * -1 on error (errno set)
16032 * -2 on security error
16033 */
16034 static int
16035 #ifdef CK_ANSIC
secure_putbuf(int fd,CHAR * buf,unsigned int nbyte)16036 secure_putbuf(int fd, CHAR * buf, unsigned int nbyte)
16037 #else
16038 secure_putbuf(fd, buf, nbyte) int fd; CHAR * buf; unsigned int nbyte;
16039 #endif /* CK_ANSIC */
16040 {
16041 static char *outbuf = NULL; /* output ciphertext */
16042 #ifdef FTP_SECURITY
16043 static unsigned int bufsize = 0; /* size of outbuf */
16044 #endif /* FTP_SECURITY */
16045 ftp_int32 length = 0;
16046 ftp_uint32 net_len = 0;
16047
16048 /* Other auth types go here ... */
16049 #ifdef CK_SSL
16050 if (ssl_ftp_data_active_flag) {
16051 int count, error;
16052
16053 /* there is no need to send an empty buffer when using SSL/TLS */
16054 if ( nbyte == 0 )
16055 return(0);
16056
16057 count = SSL_write(ssl_ftp_data_con, buf, nbyte);
16058 error = SSL_get_error(ssl_ftp_data_con,count);
16059 switch (error) {
16060 case SSL_ERROR_NONE:
16061 return(0);
16062 case SSL_ERROR_WANT_WRITE:
16063 case SSL_ERROR_WANT_READ:
16064 case SSL_ERROR_SYSCALL:
16065 #ifdef NT
16066 {
16067 int gle = GetLastError();
16068 if (gle == 0)
16069 return(0);
16070 debug(F111,"secure_putbuf","SSL_ERROR_SYSCALL",gle);
16071 }
16072 #endif /* NT */
16073 case SSL_ERROR_WANT_X509_LOOKUP:
16074 case SSL_ERROR_SSL:
16075 case SSL_ERROR_ZERO_RETURN:
16076 default:
16077 SSL_shutdown(ssl_ftp_data_con);
16078 SSL_free(ssl_ftp_data_con);
16079 ssl_ftp_data_active_flag = 0;
16080 ssl_ftp_data_con = NULL;
16081 #ifdef TCPIPLIB
16082 socket_close(data);
16083 #else /* TCPIPLIB */
16084 #ifdef USE_SHUTDOWN
16085 shutdown(data, 1+1);
16086 #endif /* USE_SHUTDOWN */
16087 close(data);
16088 #endif /* TCPIPLIB */
16089 data = -1;
16090 globaldin = data;
16091 return(-1);
16092 }
16093 return(-1);
16094 }
16095 #endif /* CK_SSL */
16096
16097 #ifdef FTP_SRP
16098 if (ck_srp_is_installed() && (strcmp(auth_type, "SRP") == 0)) {
16099 if (bufsize < nbyte + FUDGE_FACTOR) {
16100 if (outbuf?
16101 (outbuf = realloc(outbuf, (unsigned) (nbyte + FUDGE_FACTOR))):
16102 (outbuf = malloc((unsigned) (nbyte + FUDGE_FACTOR)))) {
16103 bufsize = nbyte + FUDGE_FACTOR;
16104 } else {
16105 bufsize = 0;
16106 secure_error("%s (in malloc of PROT buffer)", ck_errstr());
16107 return(ERR);
16108 }
16109 }
16110 if ((length =
16111 srp_encode(ftp_dpl == FPL_PRV,
16112 (CHAR *) buf,
16113 (CHAR *) outbuf,
16114 nbyte
16115 )
16116 ) < 0) {
16117 secure_error ("srp_encode failed");
16118 return ERR;
16119 }
16120 }
16121 #endif /* FTP_SRP */
16122 #ifdef FTP_KRB4
16123 if (ck_krb4_is_installed() && (strcmp(auth_type, "KERBEROS_V4") == 0)) {
16124 struct sockaddr_in myaddr, hisaddr;
16125 GSOCKNAME_T len;
16126 len = sizeof(myaddr);
16127 if (getsockname(fd, (struct sockaddr*)&myaddr, &len) < 0) {
16128 secure_error("secure_putbuf: getsockname failed");
16129 return(ERR);
16130 }
16131 len = sizeof(hisaddr);
16132 if (getpeername(fd, (struct sockaddr*)&hisaddr, &len) < 0) {
16133 secure_error("secure_putbuf: getpeername failed");
16134 return(ERR);
16135 }
16136 if (bufsize < nbyte + FUDGE_FACTOR) {
16137 if (outbuf ?
16138 (outbuf = realloc(outbuf, (unsigned) (nbyte + FUDGE_FACTOR))):
16139 (outbuf = malloc((unsigned) (nbyte + FUDGE_FACTOR)))) {
16140 bufsize = nbyte + FUDGE_FACTOR;
16141 } else {
16142 bufsize = 0;
16143 secure_error("%s (in malloc of PROT buffer)", ck_errstr());
16144 return(ERR);
16145 }
16146 }
16147 if (ftp_dpl == FPL_PRV) {
16148 length = krb_mk_priv(buf, (CHAR *) outbuf, nbyte,
16149 ftp_sched,
16150 #ifdef KRB524
16151 ftp_cred.session,
16152 #else /* KRB524 */
16153 &ftp_cred.session,
16154 #endif /* KRB524 */
16155 &myaddr,
16156 &hisaddr
16157 );
16158 } else {
16159 length = krb_mk_safe(buf, (CHAR *) outbuf, nbyte,
16160 #ifdef KRB524
16161 ftp_cred.session,
16162 #else /* KRB524 */
16163 &ftp_cred.session,
16164 #endif /* KRB524 */
16165 &myaddr,
16166 &hisaddr
16167 );
16168 }
16169 if (length == -1) {
16170 secure_error("krb_mk_%s failed for KERBEROS_V4",
16171 ftp_dpl == FPL_PRV ? "priv" : "safe");
16172 return(ERR);
16173 }
16174 }
16175 #endif /* FTP_KRB4 */
16176 #ifdef FTP_GSSAPI
16177 if (ck_gssapi_is_installed() && (strcmp(auth_type, "GSSAPI") == 0)) {
16178 gss_buffer_desc in_buf, out_buf;
16179 OM_uint32 maj_stat, min_stat;
16180 int conf_state;
16181
16182 in_buf.value = buf;
16183 in_buf.length = nbyte;
16184 maj_stat = gss_seal(&min_stat, gcontext,
16185 (ftp_dpl == FPL_PRV), /* confidential */
16186 GSS_C_QOP_DEFAULT,
16187 &in_buf,
16188 &conf_state,
16189 &out_buf
16190 );
16191 if (maj_stat != GSS_S_COMPLETE) {
16192 /* generally need to deal */
16193 /* ie. should loop, but for now just fail */
16194 user_gss_error(maj_stat, min_stat,
16195 ftp_dpl == FPL_PRV?
16196 "GSSAPI seal failed":
16197 "GSSAPI sign failed");
16198 return(ERR);
16199 }
16200 if (bufsize < out_buf.length) {
16201 if (outbuf ?
16202 (outbuf = realloc(outbuf, (unsigned) out_buf.length)):
16203 (outbuf = malloc((unsigned) out_buf.length))) {
16204 bufsize = out_buf.length;
16205 } else {
16206 bufsize = 0;
16207 secure_error("%s (in malloc of PROT buffer)",
16208 ck_errstr());
16209 return(ERR);
16210 }
16211 }
16212 memcpy(outbuf, out_buf.value, length=out_buf.length);
16213 gss_release_buffer(&min_stat, &out_buf);
16214 }
16215 #endif /* FTP_GSSAPI */
16216 net_len = htonl((ULONG) length);
16217 if (looping_write(fd, (char *)&net_len, 4) == -1)
16218 return(-1);
16219 if (looping_write(fd, outbuf, length) != length)
16220 return(-1);
16221 return(0);
16222 }
16223
16224
16225 /* fc = 0 means to get a byte; nonzero means to initialize buffer pointers */
16226
16227 static int
secure_getbyte(fd,fc)16228 secure_getbyte(fd,fc) int fd,fc; {
16229 /* number of chars in ucbuf, pointer into ucbuf */
16230 static unsigned int nin = 0, bufp = 0;
16231 int kerror;
16232 ftp_uint32 length;
16233
16234 if (fc) {
16235 nin = bufp = 0;
16236 ucbuf[0] = NUL;
16237 return(0);
16238 }
16239 if (nin == 0) {
16240 if (iscanceled())
16241 return(-9);
16242
16243 #ifdef FTP_TIMEOUT
16244 if (check_data_connection(fd,0) < 0)
16245 return(-3);
16246 #endif /* FTP_TIMEOUT */
16247
16248 #ifdef CK_SSL
16249 if (ssl_ftp_data_active_flag) {
16250 int count, error;
16251 count = SSL_read(ssl_ftp_data_con, ucbuf, ucbufsiz);
16252 error = SSL_get_error(ssl_ftp_data_con,count);
16253 #ifdef DEBUG
16254 if (error != SSL_ERROR_NONE)
16255 debug(F101,"ftp secure_getbyte error","",error);
16256 if (count == 0)
16257 debug(F101,"ftp secure_getbyte count","",count);
16258 #endif /* DEBUG */
16259 switch (error) {
16260 case SSL_ERROR_NONE:
16261 if (count > 0) {
16262 nin = bufp = count;
16263 rpackets++;
16264 pktnum++;
16265 if (fdispla != XYFD_B) {
16266 rpktl = count;
16267 ftscreen(SCR_PT,'D',(CK_OFF_T)rpackets,NULL);
16268 }
16269 break;
16270 }
16271 case SSL_ERROR_WANT_WRITE:
16272 case SSL_ERROR_WANT_READ:
16273 case SSL_ERROR_SYSCALL:
16274 #ifdef NT
16275 {
16276 int gle = GetLastError();
16277 }
16278 #endif /* NT */
16279 case SSL_ERROR_WANT_X509_LOOKUP:
16280 case SSL_ERROR_SSL:
16281 case SSL_ERROR_ZERO_RETURN:
16282 default:
16283 nin = bufp = count = 0;
16284 SSL_shutdown(ssl_ftp_data_con);
16285 SSL_free(ssl_ftp_data_con);
16286 ssl_ftp_data_active_flag = 0;
16287 ssl_ftp_data_con = NULL;
16288 #ifdef TCPIPLIB
16289 socket_close(data);
16290 #else /* TCPIPLIB */
16291 #ifdef USE_SHUTDOWN
16292 shutdown(data, 1+1);
16293 #endif /* USE_SHUTDOWN */
16294 close(data);
16295 #endif /* TCPIPLIB */
16296 data = -1;
16297 globaldin = data;
16298 break;
16299 }
16300 } else
16301 #endif /* CK_SSL */
16302 {
16303 kerror = looping_read(fd, (char *)&length, sizeof(length));
16304 if (kerror != sizeof(length)) {
16305 secure_error("Couldn't read PROT buffer length: %d/%s",
16306 kerror,
16307 kerror == -1 ? ck_errstr()
16308 : "premature EOF"
16309 );
16310 return(ERR);
16311 }
16312 debug(F101,"secure_getbyte length","",length);
16313 debug(F101,"secure_getbyte ntohl(length)","",ntohl(length));
16314
16315 length = (ULONG) ntohl(length);
16316 if (length > maxbuf) {
16317 secure_error("Length (%d) of PROT buffer > PBSZ=%u",
16318 length,
16319 maxbuf
16320 );
16321 return(ERR);
16322 }
16323 if ((kerror = looping_read(fd, ucbuf, length)) != length) {
16324 secure_error("Couldn't read %u byte PROT buffer: %s",
16325 length,
16326 kerror == -1 ? ck_errstr() : "premature EOF"
16327 );
16328 return(ERR);
16329 }
16330
16331 /* Other auth types go here ... */
16332 #ifdef FTP_SRP
16333 if (strcmp(auth_type, "SRP") == 0) {
16334 if ((nin = bufp = srp_decode (ftp_dpl == FPL_PRV,
16335 (CHAR *) ucbuf,
16336 ucbuf,
16337 length
16338 )
16339 ) == -1) {
16340 secure_error ("srp_encode failed" );
16341 return ERR;
16342 }
16343 }
16344 #endif /* FTP_SRP */
16345 #ifdef FTP_KRB4
16346 if (strcmp(auth_type, "KERBEROS_V4") == 0) {
16347 struct sockaddr_in myaddr, hisaddr;
16348 GSOCKNAME_T len;
16349 len = sizeof(myaddr);
16350 if (getsockname(fd, (struct sockaddr*)&myaddr, &len) < 0) {
16351 secure_error("secure_putbuf: getsockname failed");
16352 return(ERR);
16353 }
16354 len = sizeof(hisaddr);
16355 if (getpeername(fd, (struct sockaddr*)&hisaddr, &len) < 0) {
16356 secure_error("secure_putbuf: getpeername failed");
16357 return(ERR);
16358 }
16359 if (ftp_dpl) {
16360 kerror = krb_rd_priv(ucbuf, length, ftp_sched,
16361 #ifdef KRB524
16362 ftp_cred.session,
16363 #else /* KRB524 */
16364 &ftp_cred.session,
16365 #endif /* KRB524 */
16366 &hisaddr, &myaddr, &ftp_msg_data);
16367 } else {
16368 kerror = krb_rd_safe(ucbuf, length,
16369 #ifdef KRB524
16370 ftp_cred.session,
16371 #else /* KRB524 */
16372 &ftp_cred.session,
16373 #endif /* KRB524 */
16374 &hisaddr, &myaddr, &ftp_msg_data);
16375 }
16376 if (kerror) {
16377 secure_error("krb_rd_%s failed for KERBEROS_V4 (%s)",
16378 ftp_dpl == FPL_PRV ? "priv" : "safe",
16379 krb_get_err_text(kerror));
16380 return(ERR);
16381 }
16382 memcpy(ucbuf,ftp_msg_data.app_data,ftp_msg_data.app_length);
16383 nin = bufp = ftp_msg_data.app_length;
16384 }
16385 #endif /* FTP_KRB4 */
16386 #ifdef FTP_GSSAPI
16387 if (strcmp(auth_type, "GSSAPI") == 0) {
16388 gss_buffer_desc xmit_buf, msg_buf;
16389 OM_uint32 maj_stat, min_stat;
16390 int conf_state;
16391
16392 xmit_buf.value = ucbuf;
16393 xmit_buf.length = length;
16394 conf_state = (ftp_dpl == FPL_PRV);
16395 /* decrypt/verify the message */
16396 maj_stat = gss_unseal(&min_stat, gcontext, &xmit_buf,
16397 &msg_buf, &conf_state, NULL);
16398 if (maj_stat != GSS_S_COMPLETE) {
16399 user_gss_error(maj_stat, min_stat,
16400 (ftp_dpl == FPL_PRV)?
16401 "failed unsealing ENC message":
16402 "failed unsealing MIC message");
16403 return ERR;
16404 }
16405 memcpy(ucbuf, msg_buf.value, nin = bufp = msg_buf.length);
16406 gss_release_buffer(&min_stat, &msg_buf);
16407 }
16408 #endif /* FTP_GSSAPI */
16409 /* Other auth types go here ... */
16410
16411 /* Update file transfer display */
16412 rpackets++;
16413 pktnum++;
16414 if (fdispla != XYFD_B) {
16415 rpktl = nin;
16416 ftscreen(SCR_PT,'D',(CK_OFF_T)rpackets,NULL);
16417 }
16418 }
16419 }
16420 if (nin == 0)
16421 return(EOF);
16422 else
16423 return(ucbuf[bufp - nin--]);
16424 }
16425
16426 /* secure_getc(fd,fc)
16427 * Call with:
16428 * fd = file descriptor for connection.
16429 * fc = 0 to get a character, fc != 0 to initialize buffer pointers.
16430 * Returns:
16431 * c>=0 on success (character value)
16432 * -1 on EOF
16433 * -2 on security error
16434 * -3 on timeout (if built with FTP_TIMEOUT defined)
16435 */
16436 static int
secure_getc(fd,fc)16437 secure_getc(fd,fc) int fd,fc; { /* file descriptor, function code */
16438
16439 if (!ftpissecure()) {
16440 static unsigned int nin = 0, bufp = 0;
16441 if (fc) {
16442 nin = bufp = 0;
16443 ucbuf[0] = NUL;
16444 return(0);
16445 }
16446 if (nin == 0) {
16447 if (iscanceled())
16448 return(-9);
16449
16450 #ifdef FTP_TIMEOUT
16451 if (check_data_connection(fd,0) < 0) {
16452 debug(F100,"secure_getc TIMEOUT","",0);
16453 nin = bufp = 0;
16454 ftp_timed_out = 1;
16455 return(-3);
16456 }
16457 #endif /* FTP_TIMEOUT */
16458
16459 nin = bufp = recv(fd,(char *)ucbuf,actualbuf,0);
16460 if ((nin == 0) || (nin == (unsigned int)-1)) {
16461 debug(F111,"secure_getc recv errno",ckitoa(nin),errno);
16462 debug(F101,"secure_getc returns EOF","",EOF);
16463 nin = bufp = 0;
16464 return(EOF);
16465 }
16466 debug(F101,"ftp secure_getc recv","",nin);
16467 ckhexdump("ftp secure_getc recv",ucbuf,16);
16468 rpackets++;
16469 pktnum++;
16470 if (fdispla != XYFD_B) {
16471 rpktl = nin;
16472 ftscreen(SCR_PT,'D',(CK_OFF_T)rpackets,NULL);
16473 }
16474 }
16475 return(ucbuf[bufp - nin--]);
16476 } else
16477 return(secure_getbyte(fd,fc));
16478 }
16479
16480 /* returns:
16481 * n>0 on success (n == # of bytes read)
16482 * 0 on EOF
16483 * -1 on error (errno set), only for FPL_CLR
16484 * -2 on security error
16485 */
16486 static int
secure_read(fd,buf,nbyte)16487 secure_read(fd, buf, nbyte) int fd; char *buf; int nbyte; {
16488 static int c = 0;
16489 int i;
16490
16491 debug(F101,"secure_read bytes requested","",nbyte);
16492 if (c == EOF)
16493 return(c = 0);
16494 for (i = 0; nbyte > 0; nbyte--) {
16495 c = secure_getc(fd,0);
16496 switch (c) {
16497 case -9: /* Canceled from keyboard */
16498 debug(F101,"ftp secure_read interrupted","",c);
16499 return(0);
16500 case ERR:
16501 debug(F101,"ftp secure_read error","",c);
16502 return(c);
16503 case EOF:
16504 debug(F101,"ftp secure_read EOF","",c);
16505 if (!i)
16506 c = 0;
16507 return(i);
16508 #ifdef FTP_TIMEOUT
16509 case -3:
16510 debug(F101,"ftp secure_read timeout","",c);
16511 return(c);
16512 #endif /* FTP_TIMEOUT */
16513 default:
16514 buf[i++] = c;
16515 }
16516 }
16517 return(i);
16518 }
16519
16520 #ifdef USE_RUSERPASS
16521 /* BEGIN_RUSERPASS
16522 *
16523 * Copyright (c) 1985 Regents of the University of California.
16524 * All rights reserved.
16525 *
16526 * Redistribution and use in source and binary forms, with or without
16527 * modification, are permitted provided that the following conditions
16528 * are met:
16529 * 1. Redistributions of source code must retain the above copyright
16530 * notice, this list of conditions and the following disclaimer.
16531 * 2. Redistributions in binary form must reproduce the above copyright
16532 * notice, this list of conditions and the following disclaimer in the
16533 * documentation and/or other materials provided with the distribution.
16534 * 3. All advertising materials mentioning features or use of this software
16535 * must display the following acknowledgement:
16536 * This product includes software developed by the University of
16537 * California, Berkeley and its contributors.
16538 * 4. Neither the name of the University nor the names of its contributors
16539 * may be used to endorse or promote products derived from this software
16540 * without specific prior written permission.
16541 *
16542 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
16543 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16544 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16545 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
16546 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
16547 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
16548 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
16549 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
16550 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
16551 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
16552 * SUCH DAMAGE.
16553 */
16554
16555 #ifndef lint
16556 static char sccsid[] = "@(#)ruserpass.c 5.3 (Berkeley) 3/1/91";
16557 #endif /* not lint */
16558
16559 #ifndef MAXHOSTNAMELEN
16560 #define MAXHOSTNAMELEN 64
16561 #endif
16562
16563 char * renvlook();
16564 static FILE * cfile;
16565
16566 #define DEFAULT 1
16567 #define LOGIN 2
16568 #define PASSWD 3
16569 #define ACCOUNT 4
16570 #define MACDEF 5
16571 #define ID 10
16572 #define MACH 11
16573
16574 static char tokval[100];
16575
16576 static struct toktab {
16577 char *tokstr;
16578 int tval;
16579 } toktab[]= {
16580 "default", DEFAULT,
16581 "login", LOGIN,
16582 "password", PASSWD,
16583 "passwd", PASSWD,
16584 "account", ACCOUNT,
16585 "machine", MACH,
16586 "macdef", MACDEF,
16587 0, 0
16588 };
16589
16590 static int
token()16591 token() {
16592 char *cp;
16593 int c;
16594 struct toktab *t;
16595
16596 if (feof(cfile))
16597 return(0);
16598 while ((c = getc(cfile)) != EOF &&
16599 (c == '\n' || c == '\t' || c == ' ' || c == ','))
16600 continue;
16601 if (c == EOF)
16602 return(0);
16603 cp = tokval;
16604 if (c == '"') {
16605 while ((c = getc(cfile)) != EOF && c != '"') {
16606 if (c == '\\')
16607 c = getc(cfile);
16608 *cp++ = c;
16609 }
16610 } else {
16611 *cp++ = c;
16612 while ((c = getc(cfile)) != EOF
16613 && c != '\n' && c != '\t' && c != ' ' && c != ',') {
16614 if (c == '\\')
16615 c = getc(cfile);
16616 *cp++ = c;
16617 }
16618 }
16619 *cp = 0;
16620 if (tokval[0] == 0)
16621 return(0);
16622 for (t = toktab; t->tokstr; t++)
16623 if (!strcmp(t->tokstr, tokval))
16624 return(t->tval);
16625 return(ID);
16626 }
16627
ruserpass(host,aname,apass,aacct)16628 ruserpass(host, aname, apass, aacct)
16629 char *host, **aname, **apass, **aacct;
16630 {
16631 char *hdir, buf[FTP_BUFSIZ], *tmp;
16632 char myname[MAXHOSTNAMELEN], *mydomain;
16633 int t, i, c, usedefault = 0;
16634 #ifdef NT
16635 struct _stat stb;
16636 #else /* NT */
16637 struct stat stb;
16638 #endif /* NT */
16639
16640 hdir = getenv("HOME");
16641 if (hdir == NULL)
16642 hdir = ".";
16643 ckmakmsg(buf,FTP_BUFSIZ,hdir,"/.netrc",NULL,NULL);
16644 cfile = fopen(buf, "r");
16645 if (cfile == NULL) {
16646 if (errno != ENOENT)
16647 perror(buf);
16648 return(0);
16649 }
16650 if (gethostname(myname, MAXHOSTNAMELEN) < 0)
16651 myname[0] = '\0';
16652 if ((mydomain = ckstrchr(myname, '.')) == NULL)
16653 mydomain = "";
16654
16655 next:
16656 while ((t = token())) switch(t) {
16657
16658 case DEFAULT:
16659 usedefault = 1;
16660 /* FALL THROUGH */
16661
16662 case MACH:
16663 if (!usedefault) {
16664 if (token() != ID)
16665 continue;
16666 /*
16667 * Allow match either for user's input host name
16668 * or official hostname. Also allow match of
16669 * incompletely-specified host in local domain.
16670 */
16671 if (ckstrcmp(host, tokval,-1,1) == 0)
16672 goto match;
16673 if (ckstrcmp(ftp_host, tokval,-1,0) == 0)
16674 goto match;
16675 if ((tmp = ckstrchr(ftp_host, '.')) != NULL &&
16676 ckstrcmp(tmp, mydomain,-1,1) == 0 &&
16677 ckstrcmp(ftp_host, tokval, tmp-ftp_host,0) == 0 &&
16678 tokval[tmp - ftp_host] == '\0')
16679 goto match;
16680 if ((tmp = ckstrchr(host, '.')) != NULL &&
16681 ckstrcmp(tmp, mydomain,-1,1) == 0 &&
16682 ckstrcmp(host, tokval, tmp - host, 0) == 0 &&
16683 tokval[tmp - host] == '\0')
16684 goto match;
16685 continue;
16686 }
16687
16688 match:
16689 while ((t = token()) && t != MACH && t != DEFAULT) switch(t) {
16690
16691 case LOGIN:
16692 if (token())
16693 if (*aname == 0) {
16694 *aname = malloc((unsigned) strlen(tokval) + 1);
16695 strcpy(*aname, tokval); /* safe */
16696 } else {
16697 if (strcmp(*aname, tokval))
16698 goto next;
16699 }
16700 break;
16701 case PASSWD:
16702 if (strcmp(*aname, "anonymous") &&
16703 fstat(fileno(cfile), &stb) >= 0 &&
16704 (stb.st_mode & 077) != 0) {
16705 fprintf(stderr, "Error - .netrc file not correct mode.\n");
16706 fprintf(stderr, "Remove password or correct mode.\n");
16707 goto bad;
16708 }
16709 if (token() && *apass == 0) {
16710 *apass = malloc((unsigned) strlen(tokval) + 1);
16711 strcpy(*apass, tokval); /* safe */
16712 }
16713 break;
16714 case ACCOUNT:
16715 if (fstat(fileno(cfile), &stb) >= 0
16716 && (stb.st_mode & 077) != 0) {
16717 fprintf(stderr, "Error - .netrc file not correct mode.\n");
16718 fprintf(stderr, "Remove account or correct mode.\n");
16719 goto bad;
16720 }
16721 if (token() && *aacct == 0) {
16722 *aacct = malloc((unsigned) strlen(tokval) + 1);
16723 strcpy(*aacct, tokval); /* safe */
16724 }
16725 break;
16726
16727 default:
16728 fprintf(stderr, "Unknown .netrc keyword %s\n", tokval);
16729 break;
16730 }
16731 goto done;
16732 }
16733
16734 done:
16735 fclose(cfile);
16736 return(0);
16737
16738 bad:
16739 fclose(cfile);
16740 return(-1);
16741 }
16742 #endif /* USE_RUSERPASS */
16743
16744 static char *radixN =
16745 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
16746
16747 static char pad = '=';
16748
16749 static int
radix_encode(inbuf,outbuf,inlen,outlen,decode)16750 radix_encode(inbuf, outbuf, inlen, outlen, decode)
16751 CHAR inbuf[], outbuf[];
16752 int inlen, *outlen, decode;
16753 {
16754 int i, j, D = 0;
16755 char *p;
16756 CHAR c = NUL;
16757
16758 if (decode) {
16759 for (i = 0, j = 0; inbuf[i] && inbuf[i] != pad; i++) {
16760 if ((p = ckstrchr(radixN, inbuf[i])) == NULL)
16761 return(1);
16762 D = p - radixN;
16763 switch (i&3) {
16764 case 0:
16765 outbuf[j] = D<<2;
16766 break;
16767 case 1:
16768 outbuf[j++] |= D>>4;
16769 outbuf[j] = (D&15)<<4;
16770 break;
16771 case 2:
16772 outbuf[j++] |= D>>2;
16773 outbuf[j] = (D&3)<<6;
16774 break;
16775 case 3:
16776 outbuf[j++] |= D;
16777 }
16778 if (j == *outlen)
16779 return(4);
16780 }
16781 switch (i&3) {
16782 case 1: return(3);
16783 case 2: if (D&15) return(3);
16784 if (strcmp((char *)&inbuf[i], "==")) return(2);
16785 break;
16786 case 3: if (D&3) return(3);
16787 if (strcmp((char *)&inbuf[i], "=")) return(2);
16788 }
16789 *outlen = j;
16790 } else {
16791 for (i = 0, j = 0; i < inlen; i++) {
16792 switch (i%3) {
16793 case 0:
16794 outbuf[j++] = radixN[inbuf[i]>>2];
16795 c = (inbuf[i]&3)<<4;
16796 break;
16797 case 1:
16798 outbuf[j++] = radixN[c|inbuf[i]>>4];
16799 c = (inbuf[i]&15)<<2;
16800 break;
16801 case 2:
16802 outbuf[j++] = radixN[c|inbuf[i]>>6];
16803 outbuf[j++] = radixN[inbuf[i]&63];
16804 c = 0;
16805 }
16806 if (j == *outlen)
16807 return(4);
16808 }
16809 if (i%3) outbuf[j++] = radixN[c];
16810 switch (i%3) {
16811 case 1: outbuf[j++] = pad;
16812 case 2: outbuf[j++] = pad;
16813 }
16814 outbuf[*outlen = j] = '\0';
16815 }
16816 return(0);
16817 }
16818
16819 static char *
radix_error(e)16820 radix_error(e) int e;
16821 {
16822 switch (e) {
16823 case 0: return("Success");
16824 case 1: return("Bad character in encoding");
16825 case 2: return("Encoding not properly padded");
16826 case 3: return("Decoded # of bits not a multiple of 8");
16827 case 4: return("Output buffer too small");
16828 default: return("Unknown error");
16829 }
16830 }
16831 /* END_RUSERPASS */
16832
16833 #ifdef FTP_SRP
16834 /*---------------------------------------------------------------------------+
16835 | |
16836 | Package: srpftp |
16837 | Author: Eugene Jhong |
16838 | |
16839 +---------------------------------------------------------------------------*/
16840
16841 /*
16842 * Copyright (c) 1997-1999 The Stanford SRP Authentication Project
16843 * All Rights Reserved.
16844 *
16845 * Permission is hereby granted, free of charge, to any person obtaining
16846 * a copy of this software and associated documentation files (the
16847 * "Software"), to deal in the Software without restriction, including
16848 * without limitation the rights to use, copy, modify, merge, publish,
16849 * distribute, sublicense, and/or sell copies of the Software, and to
16850 * permit persons to whom the Software is furnished to do so, subject to
16851 * the following conditions:
16852 *
16853 * The above copyright notice and this permission notice shall be
16854 * included in all copies or substantial portions of the Software.
16855 *
16856 * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
16857 * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
16858 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
16859 *
16860 * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
16861 * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
16862 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
16863 * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
16864 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16865 *
16866 * In addition, the following conditions apply:
16867 *
16868 * 1. Any software that incorporates the SRP authentication technology
16869 * must display the following acknowlegment:
16870 * "This product uses the 'Secure Remote Password' cryptographic
16871 * authentication system developed by Tom Wu (tjw@CS.Stanford.EDU)."
16872 *
16873 * 2. Any software that incorporates all or part of the SRP distribution
16874 * itself must also display the following acknowledgment:
16875 * "This product includes software developed by Tom Wu and Eugene
16876 * Jhong for the SRP Distribution (http://srp.stanford.edu/srp/)."
16877 *
16878 * 3. Redistributions in source or binary form must retain an intact copy
16879 * of this copyright notice and list of conditions.
16880 */
16881
16882 #define SRP_PROT_VERSION 1
16883
16884 #ifdef CK_ENCRYPTION
16885 #define SRP_DEFAULT_CIPHER CIPHER_ID_CAST5_CBC
16886 #else
16887 #define SRP_DEFAULT_CIPHER CIPHER_ID_NONE
16888 #endif /* CK_ENCRYPTION */
16889
16890 #define SRP_DEFAULT_HASH HASH_ID_SHA
16891
16892 CHAR srp_pref_cipher = CIPHER_ID_DES3_ECB;
16893 CHAR srp_pref_hash = HASH_ID_SHA;
16894
16895 static struct t_client *tc = NULL;
16896 static CHAR *skey = NULL;
16897 static krypto_context *incrypt = NULL;
16898 static krypto_context *outcrypt = NULL;
16899
16900 typedef unsigned int srp_uint32;
16901
16902 /*--------------------------------------------------------------+
16903 | srp_selcipher: select cipher |
16904 +--------------------------------------------------------------*/
16905 static int
srp_selcipher(cname)16906 srp_selcipher (cname) char *cname; {
16907 cipher_desc *cd;
16908
16909 if (!(cd = cipher_getdescbyname (cname))) {
16910 int i;
16911 CHAR *list = cipher_getlist ();
16912
16913 fprintf (stderr, "ftp: supported ciphers:\n\n");
16914 for (i = 0; i < strlen (list); i++)
16915 fprintf (stderr, " %s\n", (cipher_getdescbyid(list[i]))->name);
16916 fprintf (stderr, "\n");
16917 return -1;
16918 }
16919 srp_pref_cipher = cd->id;
16920 return 0;
16921 }
16922
16923 /*--------------------------------------------------------------+
16924 | srp_selhash: select hash |
16925 +--------------------------------------------------------------*/
16926 static int
srp_selhash(hname)16927 srp_selhash (hname) char *hname; {
16928 hash_desc *hd;
16929
16930 if (!(hd = hash_getdescbyname (hname))) {
16931 int i;
16932 CHAR *list = hash_getlist ();
16933
16934 fprintf (stderr, "ftp: supported hash functions:\n\n");
16935 for (i = 0; i < strlen (list); i++)
16936 fprintf (stderr, " %s\n", (hash_getdescbyid(list[i]))->name);
16937 fprintf (stderr, "\n");
16938 return -1;
16939 }
16940 srp_pref_hash = hd->id;
16941 return 0;
16942 }
16943
16944 /*--------------------------------------------------------------+
16945 | srp_userpass: get username and password |
16946 +--------------------------------------------------------------*/
16947 static int
srp_userpass(host)16948 srp_userpass (host) char *host; {
16949 char tmp[BUFSIZ], prompt[PROMPTSIZ];
16950 char *user;
16951
16952 user = NULL;
16953 #ifdef USE_RUSERPASS
16954 ruserpass (host, &user, &srp_pass, &srp_acct);
16955 #endif /* USE_RUSERPASS */
16956
16957 while (user == NULL) {
16958 char *myname;
16959 int ok;
16960
16961 myname = whoami();
16962 if (!myname) myname = "";
16963 if (myname[0])
16964 ckmakxmsg(prompt,PROMPTSIZ," Name (",host,":",myname,"): ",
16965 NULL,NULL,NULL,NULL,NULL,NULL,NULL);
16966 else
16967 ckmakmsg(prompt,PROMPTSIZ," Name (",host,"): ",NULL);
16968 tmp[0] = '\0';
16969 ok = uq_txt(NULL,prompt,1,NULL,tmp,BUFSIZ,NULL,
16970 DEFAULT_UQ_TIMEOUT);
16971 if (!ok || *tmp == '\0')
16972 user = myname;
16973 else
16974 user = brstrip(tmp);
16975 }
16976 ckstrncpy (srp_user, user,BUFSIZ);
16977 return(0);
16978 }
16979
16980 /*--------------------------------------------------------------+
16981 | srp_reset: reset srp information |
16982 +--------------------------------------------------------------*/
16983 static int
srp_reset()16984 srp_reset () {
16985 if (tc) { t_clientclose (tc); tc = NULL; }
16986 if (incrypt) { krypto_delete (incrypt); incrypt = NULL; }
16987 if (outcrypt) { krypto_delete (outcrypt); outcrypt = NULL; }
16988 return(0);
16989 }
16990
16991 /*--------------------------------------------------------------+
16992 | srp_ftp_auth: perform srp authentication |
16993 +--------------------------------------------------------------*/
16994 static int
srp_ftp_auth(host,user,pass)16995 srp_ftp_auth(host, user, pass)
16996 char *host;
16997 char *user;
16998 char *pass;
16999 {
17000 struct t_num *wp;
17001 struct t_num N;
17002 struct t_num g;
17003 struct t_num s;
17004 struct t_num yp;
17005 CHAR buf[FTP_BUFSIZ];
17006 CHAR tmp[FTP_BUFSIZ];
17007 CHAR *bp, *cp;
17008 int n, e, clen, blen, len, i;
17009 CHAR cid = 0;
17010 CHAR hid = 0;
17011
17012 srp_pass = srp_acct = 0;
17013
17014 n = ftpcmd("AUTH SRP",NULL,0,0,ftp_vbm);
17015 if (n != REPLY_CONTINUE) {
17016 if (ftp_deb)
17017 fprintf(stderr, "SRP rejected as an authentication type\n");
17018 return(0);
17019 } else { /* Send protocol version */
17020 CHAR vers[4];
17021 memset (vers, 0, 4);
17022 vers[3] = SRP_PROT_VERSION;
17023 if (!quiet)
17024 printf ("SRP accepted as authentication type.\n");
17025 bp = tmp; blen = 0;
17026 srp_put (vers, &bp, 4, &blen);
17027 len = FTP_BUFSIZ;
17028 if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE))
17029 goto encode_error;
17030 reply_parse = "ADAT=";
17031 n = ftpcmd("ADAT",buf,-1,-1,0);
17032 }
17033 if (n == REPLY_CONTINUE) { /* Get protocol version */
17034 bp = buf;
17035 if (!reply_parse)
17036 goto data_error;
17037 blen = FTP_BUFSIZ;
17038 if (e = radix_encode(reply_parse, bp, 0, &blen, RADIX_DECODE))
17039 goto decode_error;
17040 if (srp_get (&bp, &cp, &blen, &clen) != 4)
17041 goto data_error;
17042
17043 if (host) { /* Get username/password if needed */
17044 srp_userpass (host);
17045 } else {
17046 ckstrncpy (srp_user, user, BUFSIZ);
17047 srp_pass = pass;
17048 }
17049 bp = tmp; blen = 0; /* Send username */
17050 srp_put (srp_user, &bp, strlen (srp_user), &blen);
17051 len = FTP_BUFSIZ;
17052 if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE))
17053 goto encode_error;
17054 reply_parse = "ADAT=";
17055 n = ftpcmd("ADAT",buf,-1,-1,0);
17056 }
17057 if (n == REPLY_CONTINUE) { /* Get N, g and s */
17058 bp = buf;
17059 if (!reply_parse)
17060 goto data_error;
17061 blen = FTP_BUFSIZ;
17062 if (e = radix_encode (reply_parse, bp, 0, &blen, RADIX_DECODE))
17063 goto decode_error;
17064 if (srp_get (&bp, &(N.data), &blen, &(N.len)) < 0)
17065 goto data_error;
17066 if (srp_get (&bp, &(g.data), &blen, &(g.len)) < 0)
17067 goto data_error;
17068 if (srp_get (&bp, &(s.data), &blen, &(s.len)) < 0)
17069 goto data_error;
17070 if ((tc = t_clientopen (srp_user, &N, &g, &s)) == NULL) {
17071 fprintf (stderr, "Unable to open SRP client structure.\n");
17072 goto bad;
17073 }
17074 wp = t_clientgenexp (tc); /* Send wp */
17075 bp = tmp; blen = 0;
17076 srp_put (wp->data, &bp, wp->len, &blen);
17077 len = FTP_BUFSIZ;
17078 if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE))
17079 goto encode_error;
17080 reply_parse = "ADAT=";
17081 n = ftpcmd("ADAT",buf,-1,-1,0);
17082 }
17083 if (n == REPLY_CONTINUE) { /* Get yp */
17084 bp = buf;
17085 if (!reply_parse)
17086 goto data_error;
17087 blen = FTP_BUFSIZ;
17088 if (e = radix_encode (reply_parse, bp, 0, &blen, RADIX_DECODE))
17089 goto decode_error;
17090 if (srp_get (&bp, &(yp.data), &blen, &(yp.len)) < 0)
17091 goto data_error;
17092 if (!srp_pass) {
17093 static char ftppass[PASSBUFSIZ];
17094 int ok;
17095 setint();
17096 ok = uq_txt(NULL," SRP Password: ",2,NULL,ftppass,PASSBUFSIZ,NULL,
17097 DEFAULT_UQ_TIMEOUT);
17098 if (ok)
17099 srp_pass = brstrip(ftppass);
17100 }
17101 t_clientpasswd (tc, srp_pass);
17102 memset (srp_pass, 0, strlen (srp_pass));
17103 skey = t_clientgetkey (tc, &yp); /* Send response */
17104 bp = tmp; blen = 0;
17105 srp_put (t_clientresponse (tc), &bp, 20, &blen);
17106 len = FTP_BUFSIZ;
17107 if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE))
17108 goto encode_error;
17109 reply_parse = "ADAT=";
17110 n = ftpcmd("ADAT",buf,-1,-1,0);
17111 }
17112 if (n == REPLY_CONTINUE) { /* Get response */
17113 bp = buf;
17114 if (!reply_parse)
17115 goto data_error;
17116 blen = FTP_BUFSIZ;
17117 if (e = radix_encode (reply_parse, bp, 0, &blen, RADIX_DECODE))
17118 goto encode_error;
17119 if (srp_get (&bp, &cp, &blen, &clen) != 20)
17120 goto data_error;
17121 if (t_clientverify (tc, cp)) {
17122 fprintf (stderr, "WARNING: bad response to client challenge.\n");
17123 goto bad;
17124 }
17125 bp = tmp; blen = 0; /* Send nothing */
17126 srp_put ("\0", &bp, 1, &blen);
17127 len = FTP_BUFSIZ;
17128 if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE))
17129 goto encode_error;
17130 reply_parse = "ADAT=";
17131 n = ftpcmd("ADAT",buf,-1,-1,0);
17132 }
17133 if (n == REPLY_CONTINUE) { /* Get cipher & hash lists, seqnum */
17134 CHAR seqnum[4];
17135 CHAR *clist;
17136 CHAR *hlist;
17137 CHAR *p1;
17138 int clist_len, hlist_len;
17139 bp = buf;
17140 if (!reply_parse)
17141 goto data_error;
17142 blen = FTP_BUFSIZ;
17143 if (e = radix_encode (reply_parse, bp, 0, &blen, RADIX_DECODE))
17144 goto encode_error;
17145 if (srp_get (&bp, &clist, &blen, &clist_len) < 0)
17146 goto data_error;
17147 if (srp_get (&bp, &hlist, &blen, &hlist_len) < 0)
17148 goto data_error;
17149 if (srp_get (&bp, &cp, &blen, &clen) != 4)
17150 goto data_error;
17151 memcpy (seqnum, cp, 4);
17152 if (cipher_supported (clist, srp_pref_cipher)) /* Choose cipher */
17153 cid = srp_pref_cipher;
17154 if (!cid && cipher_supported (clist, SRP_DEFAULT_CIPHER))
17155 cid = SRP_DEFAULT_CIPHER;
17156 if (!cid) {
17157 CHAR *loclist = cipher_getlist ();
17158 for (i = 0; i < strlen (loclist); i++)
17159 if (cipher_supported (clist, loclist[i])) {
17160 cid = loclist[i];
17161 break;
17162 }
17163 }
17164 if (!cid) {
17165 fprintf (stderr, "Unable to agree on cipher.\n");
17166 goto bad;
17167 }
17168 /* Choose hash */
17169
17170 if (srp_pref_hash && hash_supported (hlist, srp_pref_hash))
17171 hid = srp_pref_hash;
17172
17173 if (!hid && hash_supported (hlist, SRP_DEFAULT_HASH))
17174 hid = SRP_DEFAULT_HASH;
17175
17176 if (!hid) {
17177 CHAR *loclist = hash_getlist ();
17178 for (i = 0; i < strlen (loclist); i++)
17179 if (hash_supported (hlist, loclist[i])) {
17180 hid = loclist[i];
17181 break;
17182 }
17183 }
17184 if (!hid) {
17185 fprintf (stderr, "Unable to agree on hash.\n");
17186 goto bad;
17187 }
17188 /* Set incrypt */
17189
17190 if (!(incrypt = krypto_new (cid, hid, skey, 20, NULL, 0, seqnum,
17191 KRYPTO_DECODE)))
17192 goto bad;
17193
17194 /* Generate random number for outkey and outseqnum */
17195
17196 t_random (seqnum, 4);
17197
17198 /* Send cid, hid, outkey, outseqnum */
17199
17200 bp = tmp; blen = 0;
17201 srp_put (&cid, &bp, 1, &blen);
17202 srp_put (&hid, &bp, 1, &blen);
17203 srp_put (seqnum, &bp, 4, &blen);
17204 len = FTP_BUFSIZ;
17205 if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE))
17206 goto encode_error;
17207 reply_parse = "ADAT=";
17208 n = ftpcmd("ADAT",buf,-1,-1,0);
17209
17210 /* Set outcrypt */
17211
17212 if (!(outcrypt = krypto_new (cid, hid, skey+20, 20, NULL, 0, seqnum,
17213 KRYPTO_ENCODE)))
17214 goto bad;
17215
17216 t_clientclose (tc);
17217 tc = NULL;
17218 }
17219 if (n != REPLY_COMPLETE)
17220 goto bad;
17221
17222 if (ftp_vbm) {
17223 if (ftp_deb)
17224 printf("\n");
17225 printf ("SRP authentication succeeded.\n");
17226 printf ("Using cipher %s and hash function %s.\n",
17227 (cipher_getdescbyid(cid))->name,
17228 (hash_getdescbyid(hid))->name
17229 );
17230 }
17231 reply_parse = NULL;
17232 auth_type = "SRP";
17233 return(1);
17234
17235 encode_error:
17236 fprintf (stderr, "Base 64 encoding failed: %s.\n", radix_error (e));
17237 goto bad;
17238
17239 decode_error:
17240 fprintf (stderr, "Base 64 decoding failed: %s.\n", radix_error (e));
17241 goto bad;
17242
17243 data_error:
17244 fprintf (stderr, "Unable to unmarshal authentication data.\n");
17245 goto bad;
17246
17247 bad:
17248 fprintf (stderr, "SRP authentication failed, trying regular login.\n");
17249 reply_parse = NULL;
17250 return(0);
17251 }
17252
17253 /*--------------------------------------------------------------+
17254 | srp_put: put item to send buffer |
17255 +--------------------------------------------------------------*/
17256 static int
srp_put(in,out,inlen,outlen)17257 srp_put (in, out, inlen, outlen)
17258 CHAR *in;
17259 CHAR **out;
17260 int inlen;
17261 int *outlen;
17262 {
17263 srp_uint32 net_len;
17264
17265 net_len = htonl (inlen);
17266 memcpy (*out, &net_len, 4);
17267
17268 *out += 4; *outlen += 4;
17269
17270 memcpy (*out, in, inlen);
17271
17272 *out += inlen; *outlen += inlen;
17273 return(0);
17274 }
17275
17276 /*--------------------------------------------------------------+
17277 | srp_get: get item from receive buffer |
17278 +--------------------------------------------------------------*/
17279 static int
srp_get(in,out,inlen,outlen)17280 srp_get (in, out, inlen, outlen)
17281 CHAR **in;
17282 CHAR **out;
17283 int *inlen;
17284 int *outlen;
17285 {
17286 srp_uint32 net_len;
17287
17288 if (*inlen < 4) return -1;
17289
17290 memcpy (&net_len, *in, 4); *inlen -= 4; *in += 4;
17291 *outlen = ntohl (net_len);
17292
17293 if (*inlen < *outlen) return -1;
17294
17295 *out = *in; *inlen -= *outlen; *in += *outlen;
17296
17297 return *outlen;
17298 }
17299
17300 /*--------------------------------------------------------------+
17301 | srp_encode: encode control message |
17302 +--------------------------------------------------------------*/
17303 static int
srp_encode(private,in,out,len)17304 srp_encode (private, in, out, len)
17305 int private;
17306 CHAR *in;
17307 CHAR *out;
17308 unsigned len;
17309 {
17310 if (private)
17311 return krypto_msg_priv (outcrypt, in, out, len);
17312 else
17313 return krypto_msg_safe (outcrypt, in, out, len);
17314 }
17315
17316 /*--------------------------------------------------------------+
17317 | srp_decode: decode control message |
17318 +--------------------------------------------------------------*/
17319 static int
srp_decode(private,in,out,len)17320 srp_decode (private, in, out, len)
17321 int private;
17322 CHAR *in;
17323 CHAR *out;
17324 unsigned len;
17325 {
17326 if (private)
17327 return krypto_msg_priv (incrypt, in, out, len);
17328 else
17329 return krypto_msg_safe (incrypt, in, out, len);
17330 }
17331
17332 #endif /* FTP_SRP */
17333
17334
17335
17336 #ifdef NOT_USED
17337 /*
17338 The following code is from the Unix FTP client. Be sure to
17339 make sure that the functionality is not lost. Especially
17340 the Proxy stuff even though we have not yet implemented it.
17341 */
17342
17343 /* Send multiple files */
17344
17345 static int
ftp_mput(argc,argv)17346 ftp_mput(argc, argv) int argc; char **argv; {
17347 register int i;
17348 sig_t oldintr;
17349 int ointer;
17350 char *tp;
17351 sigtype mcancel();
17352
17353 if (argc < 2 && !another(&argc, &argv, "local-files")) {
17354 printf("usage: %s local-files\n", argv[0]);
17355 ftpcode = -1;
17356 return;
17357 }
17358 mname = argv[0];
17359 mflag = 1;
17360 oldintr = signal(SIGINT, mcancel);
17361
17362 /* Replace with calls to cc_execute() */
17363 setjmp(jcancel);
17364 #ifdef FTP_PROXY
17365 if (proxy) {
17366 char *cp, *tp2, tmpbuf[CKMAXPATH];
17367
17368 while ((cp = remglob(argv,0)) != NULL) {
17369 if (*cp == 0) {
17370 mflag = 0;
17371 continue;
17372 }
17373 if (mflag && confirm(argv[0], cp)) {
17374 tp = cp;
17375 if (mcase) {
17376 while (*tp && !islower(*tp)) {
17377 tp++;
17378 }
17379 if (!*tp) {
17380 tp = cp;
17381 tp2 = tmpbuf;
17382 while ((*tp2 = *tp) != 0) {
17383 if (isupper(*tp2)) {
17384 *tp2 = 'a' + *tp2 - 'A';
17385 }
17386 tp++;
17387 tp2++;
17388 }
17389 }
17390 tp = tmpbuf;
17391 }
17392 if (ntflag) {
17393 tp = dotrans(tp);
17394 }
17395 if (mapflag) {
17396 tp = domap(tp);
17397 }
17398 sendrequest((sunique) ? "STOU" : "STOR", cp, tp, 0, -1, -1, 0);
17399 if (!mflag && fromatty) {
17400 ointer = interactive;
17401 interactive = 1;
17402 if (confirm("Continue with","mput")) {
17403 mflag++;
17404 }
17405 interactive = ointer;
17406 }
17407 }
17408 }
17409 signal(SIGINT, oldintr);
17410 mflag = 0;
17411 return;
17412 }
17413 #endif /* FTP_PROXY */
17414 for (i = 1; i < argc; i++) {
17415 register char **cpp, **gargs;
17416
17417 if (mflag && confirm(argv[0], argv[i])) {
17418 tp = argv[i];
17419 sendrequest((ftp_usn) ? "STOU" : "STOR", argv[i], tp, 0,-1,-1, 0);
17420 if (!mflag && fromatty) {
17421 ointer = interactive;
17422 interactive = 1;
17423 if (confirm("Continue with","mput")) {
17424 mflag++;
17425 }
17426 interactive = ointer;
17427 }
17428 }
17429 continue;
17430
17431 gargs = ftpglob(argv[i]);
17432 if (globerr != NULL) {
17433 printf("%s\n", globerr);
17434 if (gargs) {
17435 blkfree(gargs);
17436 free((char *)gargs);
17437 }
17438 continue;
17439 }
17440 for (cpp = gargs; cpp && *cpp != NULL; cpp++) {
17441 if (mflag && confirm(argv[0], *cpp)) {
17442 tp = *cpp;
17443 sendrequest((sunique) ? "STOU":"STOR", *cpp, tp, 0, -1, -1, 0);
17444 if (!mflag && fromatty) {
17445 ointer = interactive;
17446 interactive = 1;
17447 if (confirm("Continue with","mput")) {
17448 mflag++;
17449 }
17450 interactive = ointer;
17451 }
17452 }
17453 }
17454 if (gargs != NULL) {
17455 blkfree(gargs);
17456 free((char *)gargs);
17457 }
17458 }
17459 signal(SIGINT, oldintr);
17460 mflag = 0;
17461 }
17462
17463 /* Get multiple files */
17464
17465 static int
ftp_mget(argc,argv)17466 ftp_mget(argc, argv) int argc; char **argv; {
17467 int rc = -1;
17468 sig_t oldintr;
17469 int ointer;
17470 char *cp, *tp, *tp2, tmpbuf[CKMAXPATH];
17471 sigtype mcancel();
17472
17473 if (argc < 2 && !another(&argc, &argv, "remote-files")) {
17474 printf("usage: %s remote-files\n", argv[0]);
17475 ftpcode = -1;
17476 return(-1);
17477 }
17478 mname = argv[0];
17479 mflag = 1;
17480 oldintr = signal(SIGINT,mcancel);
17481 /* Replace with calls to cc_execute() */
17482 setjmp(jcancel);
17483 while ((cp = remglob(argv,proxy)) != NULL) {
17484 if (*cp == '\0') {
17485 mflag = 0;
17486 continue;
17487 }
17488 if (mflag && confirm(argv[0], cp)) {
17489 tp = cp;
17490 if (mcase) {
17491 while (*tp && !islower(*tp)) {
17492 tp++;
17493 }
17494 if (!*tp) {
17495 tp = cp;
17496 tp2 = tmpbuf;
17497 while ((*tp2 = *tp) != 0) {
17498 if (isupper(*tp2)) {
17499 *tp2 = 'a' + *tp2 - 'A';
17500 }
17501 tp++;
17502 tp2++;
17503 }
17504 }
17505 tp = tmpbuf;
17506 }
17507 rc = (recvrequest("RETR", tp, cp, "wb",
17508 tp != cp || !interactive) == 0,0,NULL,0,0,0);
17509 if (!mflag && fromatty) {
17510 ointer = interactive;
17511 interactive = 1;
17512 if (confirm("Continue with","mget")) {
17513 mflag++;
17514 }
17515 interactive = ointer;
17516 }
17517 }
17518 }
17519 signal(SIGINT,oldintr);
17520 mflag = 0;
17521 return(rc);
17522 }
17523
17524 /* Delete multiple files */
17525
17526 static int
mdelete(argc,argv)17527 mdelete(argc, argv) int argc; char **argv; {
17528 sig_t oldintr;
17529 int ointer;
17530 char *cp;
17531 sigtype mcancel();
17532
17533 if (argc < 2 && !another(&argc, &argv, "remote-files")) {
17534 printf("usage: %s remote-files\n", argv[0]);
17535 ftpcode = -1;
17536 return(-1);
17537 }
17538 mname = argv[0];
17539 mflag = 1;
17540 oldintr = signal(SIGINT, mcancel);
17541 /* Replace with calls to cc_execute() */
17542 setjmp(jcancel);
17543 while ((cp = remglob(argv,0)) != NULL) {
17544 if (*cp == '\0') {
17545 mflag = 0;
17546 continue;
17547 }
17548 if (mflag && confirm(argv[0], cp)) {
17549 rc = (ftpcmd("DELE",cp,-1,-1,ftp_vbm) == REPLY_COMPLETE);
17550 if (!mflag && fromatty) {
17551 ointer = interactive;
17552 interactive = 1;
17553 if (confirm("Continue with", "mdelete")) {
17554 mflag++;
17555 }
17556 interactive = ointer;
17557 }
17558 }
17559 }
17560 signal(SIGINT, oldintr);
17561 mflag = 0;
17562 return(rc);
17563 }
17564
17565 /* Get a directory listing of multiple remote files */
17566
17567 static int
mls(argc,argv)17568 mls(argc, argv) int argc; char **argv; {
17569 sig_t oldintr;
17570 int ointer, i;
17571 char *cmd, mode[1], *dest;
17572 sigtype mcancel();
17573 int rc = -1;
17574
17575 if (argc < 2 && !another(&argc, &argv, "remote-files"))
17576 goto usage;
17577 if (argc < 3 && !another(&argc, &argv, "local-file")) {
17578 usage:
17579 printf("usage: %s remote-files local-file\n", argv[0]);
17580 ftpcode = -1;
17581 return(-1);
17582 }
17583 dest = argv[argc - 1];
17584 argv[argc - 1] = NULL;
17585 if (strcmp(dest, "-") && *dest != '|')
17586 if (!globulize(&dest) ||
17587 !confirm("output to local-file:", dest)) {
17588 ftpcode = -1;
17589 return(-1);
17590 }
17591 cmd = argv[0][1] == 'l' ? "NLST" : "LIST";
17592 mname = argv[0];
17593 mflag = 1;
17594 oldintr = signal(SIGINT, mcancel);
17595 /* Replace with calls to cc_execute() */
17596 setjmp(jcancel);
17597 for (i = 1; mflag && i < argc-1; ++i) {
17598 *mode = (i == 1) ? 'w' : 'a';
17599 rc = recvrequest(cmd, dest, argv[i], mode, 0,0,NULL,0,0,0);
17600 if (!mflag && fromatty) {
17601 ointer = interactive;
17602 interactive = 1;
17603 if (confirm("Continue with", argv[0])) {
17604 mflag ++;
17605 }
17606 interactive = ointer;
17607 }
17608 }
17609 signal(SIGINT, oldintr);
17610 mflag = 0;
17611 return(rc);
17612 }
17613
17614 static char *
remglob(argv,doswitch)17615 remglob(argv,doswitch) char *argv[]; int doswitch; {
17616 char temp[16];
17617 static char buf[CKMAXPATH];
17618 static FILE *ftemp = NULL;
17619 static char **args;
17620 int oldhash;
17621 char *cp, *mode;
17622
17623 if (!mflag) {
17624 if (!doglob) {
17625 args = NULL;
17626 } else {
17627 if (ftemp) {
17628 (void) fclose(ftemp);
17629 ftemp = NULL;
17630 }
17631 }
17632 return(NULL);
17633 }
17634 if (!doglob) {
17635 if (args == NULL)
17636 args = argv;
17637 if ((cp = *++args) == NULL)
17638 args = NULL;
17639 return(cp);
17640 }
17641 if (ftemp == NULL) {
17642 (void) strcpy(temp, _PATH_TMP);
17643 #ifdef MKTEMP
17644 #ifndef MKSTEMP
17645 (void) mktemp(temp);
17646 #endif /* MKSTEMP */
17647 #endif /* MKTEMP */
17648 verbose = 0;
17649 oldhash = hash, hash = 0;
17650 #ifdef FTP_PROXY
17651 if (doswitch) {
17652 pswitch(!proxy);
17653 }
17654 #endif /* FTP_PROXY */
17655 for (mode = "wb"; *++argv != NULL; mode = "ab")
17656 recvrequest ("NLST", temp, *argv, mode, 0);
17657 #ifdef FTP_PROXY
17658 if (doswitch) {
17659 pswitch(!proxy);
17660 }
17661 #endif /* FTP_PROXY */
17662 hash = oldhash;
17663 ftemp = fopen(temp, "r");
17664 unlink(temp);
17665 if (ftemp == NULL && (!dpyactive || ftp_deb)) {
17666 printf("Can't find list of remote files, oops\n");
17667 return(NULL);
17668 }
17669 }
17670 if (fgets(buf, CKMAXPATH, ftemp) == NULL) {
17671 fclose(ftemp), ftemp = NULL;
17672 return(NULL);
17673 }
17674 if ((cp = ckstrchr(buf,'\n')) != NULL)
17675 *cp = '\0';
17676 return(buf);
17677 }
17678 #endif /* NOT_USED */
17679 #endif /* TCPSOCKET (top of file) */
17680 #endif /* SYSFTP (top of file) */
17681 #endif /* NOFTP (top of file) */
17682