* Copyright (c) 1985, 1989 Regents of the University of California.
* %sccs.include.redist.c%
static char sccsid
[] = "@(#)ftp.c 5.35 (Berkeley) %G%";
#include <netinet/in_systm.h>
struct sockaddr_in hisctladdr
;
struct sockaddr_in data_addr
;
struct sockaddr_in myctladdr
;
extern int connected
, errno
;
register struct hostent
*hp
= 0;
static char hostnamebuf
[80];
bzero((char *)&hisctladdr
, sizeof (hisctladdr
));
hisctladdr
.sin_addr
.s_addr
= inet_addr(host
);
if (hisctladdr
.sin_addr
.s_addr
!= -1) {
hisctladdr
.sin_family
= AF_INET
;
(void) strncpy(hostnamebuf
, host
, sizeof(hostnamebuf
));
hp
= gethostbyname(host
);
fprintf(stderr
, "ftp: %s: ", host
);
hisctladdr
.sin_family
= hp
->h_addrtype
;
bcopy(hp
->h_addr_list
[0],
(caddr_t
)&hisctladdr
.sin_addr
, hp
->h_length
);
(void) strncpy(hostnamebuf
, hp
->h_name
, sizeof(hostnamebuf
));
s
= socket(hisctladdr
.sin_family
, SOCK_STREAM
, 0);
hisctladdr
.sin_port
= port
;
while (connect(s
, (struct sockaddr
*)&hisctladdr
, sizeof (hisctladdr
)) < 0) {
if (hp
&& hp
->h_addr_list
[1]) {
extern char *inet_ntoa();
fprintf(stderr
, "ftp: connect to address %s: ",
inet_ntoa(hisctladdr
.sin_addr
));
bcopy(hp
->h_addr_list
[0],
(caddr_t
)&hisctladdr
.sin_addr
, hp
->h_length
);
fprintf(stdout
, "Trying %s...\n",
inet_ntoa(hisctladdr
.sin_addr
));
s
= socket(hisctladdr
.sin_family
, SOCK_STREAM
, 0);
len
= sizeof (myctladdr
);
if (getsockname(s
, (struct sockaddr
*)&myctladdr
, &len
) < 0) {
perror("ftp: getsockname");
if (setsockopt(s
, IPPROTO_IP
, IP_TOS
, (char *)&tos
, sizeof(int)) < 0)
perror("Notice: set type-of-service failed: %m");
if (cin
== NULL
|| cout
== NULL
) {
fprintf(stderr
, "ftp: fdopen failed.\n");
printf("Connected to %s.\n", hostname
);
if (getreply(0) > 2) { /* read startup message from server */
if (setsockopt(s
, SOL_SOCKET
, SO_OOBINLINE
, (char *)&on
, sizeof(on
))
perror("ftp: setsockopt");
#endif /* SO_OOBINLINE */
char *user
, *pass
, *acct
, *getlogin(), *getpass();
if (ruserpass(host
, &user
, &pass
, &acct
) < 0) {
char *myname
= getlogin();
struct passwd
*pp
= getpwuid(getuid());
printf("Name (%s:%s): ", host
, myname
);
printf("Name (%s): ", host
);
(void) fgets(tmp
, sizeof(tmp
) - 1, stdin
);
tmp
[strlen(tmp
) - 1] = '\0';
n
= command("USER %s", user
);
pass
= getpass("Password:");
n
= command("PASS %s", pass
);
acct
= getpass("Account:");
n
= command("ACCT %s", acct
);
fprintf(stderr
, "Login failed.\n");
if (!aflag
&& acct
!= NULL
)
(void) command("ACCT %s", acct
);
for (n
= 0; n
< macnum
; ++n
) {
if (!strcmp("init", macros
[n
].mac_name
)) {
(void) strcpy(line
, "$init");
fmt
= va_arg(ap
, char *);
if (strncmp("PASS ", fmt
, 5) == 0)
vfprintf(stdout
, fmt
, ap
);
perror ("No control connection for command");
oldintr
= signal(SIGINT
, cmdabort
);
fmt
= va_arg(ap
, char *);
r
= getreply(!strcmp(fmt
, "QUIT"));
if (abrtflag
&& oldintr
!= SIG_IGN
)
(void) signal(SIGINT
, oldintr
);
char reply_string
[BUFSIZ
]; /* last line of previous reply */
int originalcode
= 0, continuation
= 0;
oldintr
= signal(SIGINT
, cmdabort
);
while ((c
= getc(cin
)) != '\n') {
if (c
== IAC
) { /* handle telnet commands */
fprintf(cout
, "%c%c%c", IAC
, DONT
, c
);
fprintf(cout
, "%c%c%c", IAC
, WONT
, c
);
(void) signal(SIGINT
,oldintr
);
printf("421 Service not available, remote server has closed connection\n");
if (c
!= '\r' && (verbose
> 0 ||
(verbose
> -1 && n
== '5' && dig
> 4))) {
(dig
== 1 || dig
== 5 && verbose
== 0))
if (dig
< 4 && isdigit(c
))
code
= code
* 10 + (c
- '0');
if (!pflag
&& code
== 227)
if (dig
> 4 && pflag
== 1 && isdigit(c
))
if (c
!= '\r' && c
!= ')')
if (dig
== 4 && c
== '-') {
if (cp
< &reply_string
[sizeof(reply_string
) - 1])
if (verbose
> 0 || verbose
> -1 && n
== '5') {
if (continuation
&& code
!= originalcode
) {
(void) signal(SIGINT
,oldintr
);
if (code
== 421 || originalcode
== 421)
if (abrtflag
&& oldintr
!= cmdabort
&& oldintr
!= SIG_IGN
)
return(select(32, mask
, (struct fd_set
*) 0, (struct fd_set
*) 0, &t
));
printf("\nsend aborted\nwaiting for remote to finish abort\n");
sendrequest(cmd
, local
, remote
, printnames
)
char *cmd
, *local
, *remote
;
struct timeval start
, stop
;
FILE *fin
, *dout
= 0, *popen();
int (*closefunc
)(), pclose(), fclose();
long bytes
= 0, hashbytes
= HASHBYTES
;
char *lmode
, buf
[BUFSIZ
], *bufp
;
if (verbose
&& printnames
) {
if (local
&& *local
!= '-')
printf("local: %s ", local
);
printf("remote: %s\n", remote
);
proxtrans(cmd
, local
, remote
);
(void) signal(SIGINT
,oldintr
);
(void) signal(SIGPIPE
,oldintp
);
oldintr
= signal(SIGINT
, abortsend
);
if (strcmp(local
, "-") == 0)
else if (*local
== '|') {
oldintp
= signal(SIGPIPE
,SIG_IGN
);
fin
= popen(local
+ 1, "r");
(void) signal(SIGINT
, oldintr
);
(void) signal(SIGPIPE
, oldintp
);
fprintf(stderr
, "local: %s: %s\n", local
,
(void) signal(SIGINT
, oldintr
);
if (fstat(fileno(fin
), &st
) < 0 ||
(st
.st_mode
&S_IFMT
) != S_IFREG
) {
fprintf(stdout
, "%s: not a plain file.\n", local
);
(void) signal(SIGINT
, oldintr
);
(void) signal(SIGINT
, oldintr
);
(void) signal(SIGPIPE
, oldintp
);
if (command("%s %s", cmd
, remote
) != PRELIM
) {
(void) signal(SIGINT
, oldintr
);
(void) signal(SIGPIPE
, oldintp
);
if (command("%s", cmd
) != PRELIM
) {
(void) signal(SIGINT
, oldintr
);
(void) signal(SIGPIPE
, oldintp
);
(void) gettimeofday(&start
, (struct timezone
*)0);
oldintp
= signal(SIGPIPE
, SIG_IGN
);
while ((c
= read(fileno(fin
), buf
, sizeof (buf
))) > 0) {
for (bufp
= buf
; c
> 0; c
-= d
, bufp
+= d
)
if ((d
= write(fileno(dout
), bufp
, c
)) <= 0)
for (bufp
= buf
; c
> 0; c
-= d
, bufp
+= d
)
if ((d
= write(fileno(dout
), bufp
, c
)) <= 0)
while (bytes
>= hashbytes
) {
fprintf(stderr
, "local: %s: %s\n", local
,
fprintf(stderr
, "netout: write returned 0?\n");
while ((c
= getc(fin
)) != EOF
) {
while (hash
&& (bytes
>= hashbytes
)) {
/* (void) putc('\0', dout); /* this violates rfc */
fprintf(stderr
, "local: %s: %s\n", local
,
(void) gettimeofday(&stop
, (struct timezone
*)0);
(void) signal(SIGINT
, oldintr
);
(void) signal(SIGPIPE
, oldintp
);
ptransfer("sent", bytes
, &start
, &stop
);
(void) gettimeofday(&stop
, (struct timezone
*)0);
(void) signal(SIGINT
, oldintr
);
(void) signal(SIGPIPE
, oldintp
);
if (closefunc
!= NULL
&& fin
!= NULL
)
ptransfer("sent", bytes
, &start
, &stop
);
printf("\nreceive aborted\nwaiting for remote to finish abort\n");
recvrequest(cmd
, local
, remote
, lmode
, printnames
)
char *cmd
, *local
, *remote
, *lmode
;
FILE *fout
, *din
= 0, *popen();
char *bufp
, *gunique(), msg
;
long bytes
= 0, hashbytes
= HASHBYTES
;
struct timeval start
, stop
;
is_retr
= strcmp(cmd
, "RETR") == 0;
if (is_retr
&& verbose
&& printnames
) {
if (local
&& *local
!= '-')
printf("local: %s ", local
);
printf("remote: %s\n", remote
);
proxtrans(cmd
, local
, remote
);
tcrflag
= !crflag
&& is_retr
;
(void) signal(SIGINT
, oldintr
);
oldintr
= signal(SIGINT
, abortrecv
);
if (strcmp(local
, "-") && *local
!= '|') {
if (access(local
, 2) < 0) {
char *dir
= rindex(local
, '/');
if (errno
!= ENOENT
&& errno
!= EACCES
) {
fprintf(stderr
, "local: %s: %s\n", local
,
(void) signal(SIGINT
, oldintr
);
d
= access(dir
? local
: ".", 2);
fprintf(stderr
, "local: %s: %s\n", local
,
(void) signal(SIGINT
, oldintr
);
if (!runique
&& errno
== EACCES
&&
chmod(local
, 0600) < 0) {
fprintf(stderr
, "local: %s: %s\n", local
,
(void) signal(SIGINT
, oldintr
);
(void) signal(SIGINT
, oldintr
);
if (runique
&& errno
== EACCES
&&
(local
= gunique(local
)) == NULL
) {
(void) signal(SIGINT
, oldintr
);
else if (runique
&& (local
= gunique(local
)) == NULL
) {
(void) signal(SIGINT
, oldintr
);
} else if (curtype
!= type
)
(void) signal(SIGINT
, oldintr
);
if (is_retr
&& restart_point
&&
command("REST %ld", (long) restart_point
) != CONTINUE
)
if (command("%s %s", cmd
, remote
) != PRELIM
) {
(void) signal(SIGINT
, oldintr
);
if (command("%s", cmd
) != PRELIM
) {
(void) signal(SIGINT
, oldintr
);
if (strcmp(local
, "-") == 0)
else if (*local
== '|') {
oldintp
= signal(SIGPIPE
, SIG_IGN
);
fout
= popen(local
+ 1, "w");
fout
= fopen(local
, lmode
);
fprintf(stderr
, "local: %s: %s\n", local
,
if (fstat(fileno(fout
), &st
) < 0 || st
.st_blksize
== 0)
if (st
.st_blksize
> bufsize
) {
buf
= malloc((unsigned)st
.st_blksize
);
(void) gettimeofday(&start
, (struct timezone
*)0);
while ((c
= read(fileno(din
), buf
, bufsize
)) > 0) {
if ((d
= write(fileno(fout
), buf
, c
)) != c
)
while (bytes
>= hashbytes
) {
fprintf(stderr
, "%s: short write\n", local
);
while ((c
= getc(din
)) != EOF
) {
while (hash
&& (bytes
>= hashbytes
)) {
if ((c
= getc(din
)) != '\n' || tcrflag
) {
printf("WARNING! %d bare linefeeds received in ASCII mode\n", bare_lfs
);
printf("File may not have transferred correctly.\n");
fprintf(stderr
, "local: %s: %s\n", local
,
(void) signal(SIGINT
, oldintr
);
(void) signal(SIGPIPE
, oldintp
);
(void) gettimeofday(&stop
, (struct timezone
*)0);
if (bytes
> 0 && is_retr
)
ptransfer("received", bytes
, &start
, &stop
);
/* abort using RFC959 recommended IP,SYNC sequence */
(void) gettimeofday(&stop
, (struct timezone
*)0);
(void) signal(SIGPIPE
, oldintr
);
(void) signal(SIGINT
, SIG_IGN
);
(void) signal(SIGINT
, oldintr
);
if (closefunc
!= NULL
&& fout
!= NULL
)
ptransfer("received", bytes
, &start
, &stop
);
(void) signal(SIGINT
, oldintr
);
* Need to start a listen on the data channel before we send the command,
* otherwise the server's connect may fail.
int result
, len
, tmpno
= 0;
data_addr
.sin_port
= 0; /* let system pick one */
data
= socket(AF_INET
, SOCK_STREAM
, 0);
if (setsockopt(data
, SOL_SOCKET
, SO_REUSEADDR
, (char *)&on
, sizeof (on
)) < 0) {
perror("ftp: setsockopt (reuse address)");
if (bind(data
, (struct sockaddr
*)&data_addr
, sizeof (data_addr
)) < 0) {
if (options
& SO_DEBUG
&&
setsockopt(data
, SOL_SOCKET
, SO_DEBUG
, (char *)&on
, sizeof (on
)) < 0)
perror("ftp: setsockopt (ignored)");
len
= sizeof (data_addr
);
if (getsockname(data
, (struct sockaddr
*)&data_addr
, &len
) < 0) {
perror("ftp: getsockname");
a
= (char *)&data_addr
.sin_addr
;
p
= (char *)&data_addr
.sin_port
;
#define UC(b) (((int)b)&0xff)
command("PORT %d,%d,%d,%d,%d,%d",
UC(a
[0]), UC(a
[1]), UC(a
[2]), UC(a
[3]),
if (result
== ERROR
&& sendport
== -1) {
return (result
!= COMPLETE
);
if (setsockopt(data
, IPPROTO_IP
, IP_TOS
, (char *)&on
, sizeof(int)) < 0)
perror("Notice: set type-of-service failed: %m");
(void) close(data
), data
= -1;
int s
, fromlen
= sizeof (from
), tos
;
s
= accept(data
, (struct sockaddr
*) &from
, &fromlen
);
(void) close(data
), data
= -1;
if (setsockopt(s
, IPPROTO_IP
, IP_TOS
, (char *)&tos
, sizeof(int)) < 0)
perror("Notice: set type-of-service failed: %m");
return (fdopen(data
, lmode
));
ptransfer(direction
, bytes
, t0
, t1
)
s
= td
.tv_sec
+ (td
.tv_usec
/ 1000000.);
#define nz(x) ((x) == 0 ? 1 : (x))
printf("%ld bytes %s in %.2g seconds (%.2g Kbytes/s)\n",
bytes
, direction
, s
, bs
/ 1024.);
struct timeval *tsum, *t0;
tsum->tv_sec += t0->tv_sec;
tsum->tv_usec += t0->tv_usec;
if (tsum->tv_usec > 1000000)
tsum->tv_sec++, tsum->tv_usec -= 1000000;
struct timeval
*tdiff
, *t1
, *t0
;
tdiff
->tv_sec
= t1
->tv_sec
- t0
->tv_sec
;
tdiff
->tv_usec
= t1
->tv_usec
- t0
->tv_usec
;
tdiff
->tv_sec
--, tdiff
->tv_usec
+= 1000000;
extern int proxy
, abrtflag
;
char name
[MAXHOSTNAMELEN
];
oldintr
= signal(SIGINT
, psabort
);
(void) strncpy(ip
->name
, hostname
, sizeof(ip
->name
) - 1);
ip
->name
[strlen(ip
->name
)] = '\0';
(void) strncpy(ip
->nti
, ntin
, 16);
(ip
->nti
)[strlen(ip
->nti
)] = '\0';
(void) strcpy(ntin
, op
->nti
);
(void) strncpy(ip
->nto
, ntout
, 16);
(ip
->nto
)[strlen(ip
->nto
)] = '\0';
(void) strcpy(ntout
, op
->nto
);
(void) strncpy(ip
->mi
, mapin
, MAXPATHLEN
- 1);
(ip
->mi
)[strlen(ip
->mi
)] = '\0';
(void) strcpy(mapin
, op
->mi
);
(void) strncpy(ip
->mo
, mapout
, MAXPATHLEN
- 1);
(ip
->mo
)[strlen(ip
->mo
)] = '\0';
(void) strcpy(mapout
, op
->mo
);
(void) signal(SIGINT
, oldintr
);
proxtrans(cmd
, local
, remote
)
char *cmd
, *local
, *remote
;
int secndflag
= 0, prox_type
, nfnd
;
cmd2
= runique
? "STOU" : "STOR";
if ((prox_type
= type
) == 0) {
if (unix_server
&& unix_proxy
)
if (curtype
!= prox_type
)
changetype(prox_type
, 1);
if (command("PASV") != COMPLETE
) {
printf("proxy server does not support third party transfers.\n");
printf("No primary connection\n");
if (curtype
!= prox_type
)
changetype(prox_type
, 1);
if (command("PORT %s", pasv
) != COMPLETE
) {
oldintr
= signal(SIGINT
, abortpt
);
if (command("%s %s", cmd
, remote
) != PRELIM
) {
(void) signal(SIGINT
, oldintr
);
if (command("%s %s", cmd2
, local
) != PRELIM
)
(void) signal(SIGINT
, oldintr
);
printf("local: %s remote: %s\n", local
, remote
);
(void) signal(SIGINT
, SIG_IGN
);
if (strcmp(cmd
, "RETR") && !proxy
)
else if (!strcmp(cmd
, "RETR") && proxy
)
if (!cpend
&& !secndflag
) { /* only here if cmd = "STOR" (proxy=1) */
if (command("%s %s", cmd2
, local
) != PRELIM
) {
abort_remote((FILE *) NULL
);
(void) signal(SIGINT
, oldintr
);
abort_remote((FILE *) NULL
);
if (!cpend
&& !secndflag
) { /* only if cmd = "RETR" (proxy=1) */
if (command("%s %s", cmd2
, local
) != PRELIM
) {
abort_remote((FILE *) NULL
);
(void) signal(SIGINT
, oldintr
);
abort_remote((FILE *) NULL
);
FD_SET(fileno(cin
), &mask
);
if ((nfnd
= empty(&mask
, 10)) <= 0) {
(void) signal(SIGINT
, oldintr
);
FD_SET(fileno(cin
), &mask
);
if ((nfnd
= empty(&mask
,0)) < 0) {
static char new[MAXPATHLEN
];
char *cp
= rindex(local
, '/');
d
= access(cp
? local
: ".", 2);
fprintf(stderr
, "local: %s: %s\n", local
, strerror(errno
));
(void) strcpy(new, local
);
printf("runique: can't find unique file name.\n");
if ((d
= access(new, 0)) < 0)
else if (*(cp
- 2) == '.')
*(cp
- 2) = *(cp
- 2) + 1;
* send IAC in urgent mode instead of DM because 4.3BSD places oob mark
* after urgent byte rather than before as is protocol now
sprintf(buf
, "%c%c%c", IAC
, IP
, IAC
);
if (send(fileno(cout
), buf
, 3, MSG_OOB
) != 3)
fprintf(cout
,"%cABOR\r\n", DM
);
FD_SET(fileno(cin
), &mask
);
FD_SET(fileno(din
), &mask
);
if ((nfnd
= empty(&mask
, 10)) <= 0) {
if (din
&& FD_ISSET(fileno(din
), &mask
)) {
while (read(fileno(din
), buf
, BUFSIZ
) > 0)
if (getreply(0) == ERROR
&& code
== 552) {
/* 552 needed for nic style abort */