* Copyright (c) 1985, 1989 Regents of the University of California.
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
static char sccsid
[] = "@(#)ftp.c 5.29 (Berkeley) %G%";
struct sockaddr_in hisctladdr
;
struct sockaddr_in data_addr
;
struct sockaddr_in myctladdr
;
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
, &hisctladdr
, sizeof (hisctladdr
)) < 0) {
if (hp
&& hp
->h_addr_list
[1]) {
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
, (char *)&myctladdr
, &len
) < 0) {
perror("ftp: getsockname");
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
, &on
, sizeof(on
))
perror("ftp: setsockopt");
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");
int r
, (*oldintr
)(), cmdabort();
if (strncmp(fmt
, "PASS", 4) == 0)
_doprnt(fmt
, (int *)&xxx
, stdout
);
_doprnt(fmt
, &args
, stdout
);
perror ("No control connection for command");
oldintr
= signal(SIGINT
,cmdabort
);
_doprnt(fmt
, &args
, cout
);
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
)(), cmdabort();
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\n");
sendrequest(cmd
, local
, remote
, printnames
)
char *cmd
, *local
, *remote
;
FILE *fin
, *dout
= 0, *popen();
int (*closefunc
)(), pclose(), fclose(), (*oldintr
)(), (*oldintp
)();
long bytes
= 0, hashbytes
= HASHBYTES
;
struct timeval start
, stop
;
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
);
(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
, "netout: write returned 0?\n");
while ((c
= getc(fin
)) != EOF
) {
while (hash
&& (bytes
>= hashbytes
)) {
/* (void) putc('\0', dout); /* this violates rfc */
(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
);
recvrequest(cmd
, local
, remote
, mode
, printnames
)
char *cmd
, *local
, *remote
, *mode
;
FILE *fout
, *din
= 0, *popen();
int (*closefunc
)(), pclose(), fclose(), (*oldintr
)(), (*oldintp
)();
int abortrecv(), is_retr
, tcrflag
, nfnd
;
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
) {
(void) signal(SIGINT
, oldintr
);
d
= access(dir
? local
: ".", 2);
(void) signal(SIGINT
, oldintr
);
if (!runique
&& errno
== EACCES
&&
chmod(local
, 0600) < 0) {
(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
, mode
);
if (fstat(fileno(fout
), &st
) < 0 || st
.st_blksize
== 0)
if (st
.st_blksize
> bufsize
) {
buf
= malloc(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
) {
(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
);
fprintf(cout
,"%c%c",IAC
,IP
);
/* send IAC in urgent mode instead of DM because UNIX places oob mark */
/* after urgent byte rather than before as now is protocol */
if (send(fileno(cout
),&msg
,1,MSG_OOB
) != 1) {
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 ((c
= read(fileno(din
), buf
, bufsize
)) > 0)
if ((c
= getreply(0)) == ERROR
&& code
== 552) { /* needed for nic style abort */
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
, (char *)&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
);
(void) close(data
), data
= -1;
int s
, fromlen
= sizeof (from
);
s
= accept(data
, (struct sockaddr
*) &from
, &fromlen
);
(void) close(data
), data
= -1;
return (fdopen(data
, mode
));
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 (*oldintr
)(), abortpt(), prox_type
, secndflag
= 0, 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
) {
fprintf(cout
,"%c%c",IAC
,IP
);
if (send(fileno(cout
),msg
,2,MSG_OOB
) != 2)
fprintf(cout
,"ABOR\r\n");
FD_SET(fileno(cin
), &mask
);
if ((nfnd
= empty(&mask
,10)) <= 0) {
(void) signal(SIGINT
, oldintr
);
fprintf(cout
,"%c%c",IAC
,IP
);
if (send(fileno(cout
),msg
,2,MSG_OOB
) != 2)
fprintf(cout
,"ABOR\r\n");
FD_SET(fileno(cin
), &mask
);
if ((nfnd
= empty(&mask
,10)) <= 0) {
if (!cpend
&& !secndflag
) { /* only if cmd = "RETR" (proxy=1) */
if (command("%s %s", cmd2
, local
) != PRELIM
) {
fprintf(cout
,"%c%c",IAC
,IP
);
if (send(fileno(cout
),msg
,2,MSG_OOB
) != 2)
fprintf(cout
,"ABOR\r\n");
FD_SET(fileno(cin
), &mask
);
if ((nfnd
= empty(&mask
,10)) <= 0) {
(void) signal(SIGINT
, oldintr
);
fprintf(cout
,"%c%c",IAC
,IP
);
if (send(fileno(cout
),msg
,2,MSG_OOB
) != 2)
fprintf(cout
,"ABOR\r\n");
FD_SET(fileno(cin
), &mask
);
if ((nfnd
= empty(&mask
,10)) <= 0) {
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);
(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;