minix/commands/ftp/net.c
2005-04-21 14:53:53 +00:00

422 lines
8.3 KiB
C
Executable file

/* net.c
*
* This file is part of ftp.
*
*
* 01/25/96 Initial Release Michael Temari, <temari@ix.netcom.com>
*/
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <signal.h>
#include <errno.h>
#include <net/netlib.h>
#include <net/hton.h>
#include <net/gen/netdb.h>
#include <net/gen/in.h>
#include <net/gen/inet.h>
#include <net/gen/tcp.h>
#include <net/gen/tcp_io.h>
#include "ftp.h"
#include "file.h"
#include "net.h"
_PROTOTYPE(void donothing, (int sig));
static int ftpcomm_fd;
static ipaddr_t myip;
static ipaddr_t hostip;
static char host[256];
static int lpid;
void NETinit()
{
int s;
char *tcp_device;
int tcp_fd;
nwio_tcpconf_t nwio_tcpconf;
/* All this just to get our ip address */
if((tcp_device = getenv("TCP_DEVICE")) == (char *)NULL)
tcp_device = TCP_DEVICE;
tcp_fd = open(tcp_device, O_RDWR);
if(tcp_fd < 0) {
perror("ftp: Could not open tcp_device");
exit(-1);
}
s = ioctl(tcp_fd, NWIOGTCPCONF, &nwio_tcpconf);
if(s < 0) {
perror("ftp: Could not get tcp configuration");
exit(-1);
}
myip = nwio_tcpconf.nwtc_locaddr;
close(tcp_fd);
}
int DOopen()
{
nwio_tcpconf_t tcpconf;
nwio_tcpcl_t tcpcopt;
char *tcp_device;
tcpport_t port;
int s;
struct hostent *hp;
struct servent *servent;
if(linkopen) {
printf("Use \"CLOSE\" to close the connection first.\n");
return(0);
}
if(cmdargc < 2)
readline("Host: ", host, sizeof(host));
else
strncpy(host, cmdargv[1], sizeof(host));
if((servent = getservbyname("ftp", "tcp")) == (struct servent *)NULL) {
fprintf(stderr, "ftp: Could not find ftp tcp service\n");
return(-1);
}
port = (tcpport_t)servent->s_port;
hp = gethostbyname(host);
if (hp == (struct hostent *)NULL) {
hostip = (ipaddr_t)0;
printf("Unresolved host %s\n", host);
return(0);
} else
memcpy((char *) &hostip, (char *) hp->h_addr, hp->h_length);
/* This HACK allows the server to establish data connections correctly */
/* when using the loopback device to talk to ourselves */
if(hostip == inet_addr("127.0.0.1"))
hostip = myip;
if((tcp_device = getenv("TCP_DEVICE")) == NULL)
tcp_device = "/dev/tcp";
if((ftpcomm_fd = open(tcp_device, O_RDWR)) < 0) {
perror("ftp: open error on tcp device");
return(-1);
}
tcpconf.nwtc_flags = NWTC_LP_SEL | NWTC_SET_RA | NWTC_SET_RP;
tcpconf.nwtc_remaddr = hostip;
tcpconf.nwtc_remport = port;
s = ioctl(ftpcomm_fd, NWIOSTCPCONF, &tcpconf);
if(s < 0) {
perror("ftp: ioctl error on NWIOSTCPCONF");
close(ftpcomm_fd);
return(s);
}
tcpcopt.nwtcl_flags = 0;
s = ioctl(ftpcomm_fd, NWIOTCPCONN, &tcpcopt);
if(s < 0) {
perror("ftp: ioctl error on NWIOTCPCONN");
close(ftpcomm_fd);
return(s);
}
s = ioctl(ftpcomm_fd, NWIOGTCPCONF, &tcpconf);
if(s < 0) {
perror("ftp: ioctl error on NWIOGTCPCONF");
close(ftpcomm_fd);
return(s);
}
fpcommin = fdopen(ftpcomm_fd, "r");
fpcommout = fdopen(ftpcomm_fd, "w");
s = DOgetreply();
if(s < 0) {
fclose(fpcommin);
fclose(fpcommout);
close(ftpcomm_fd);
return(s);
}
if(s != 220) {
fclose(fpcommin);
fclose(fpcommout);
close(ftpcomm_fd);
return(0);
}
linkopen = 1;
return(s);
}
int DOclose()
{
if(!linkopen) {
printf("You can't close a connection that isn't open.\n");
return(0);
}
fclose(fpcommin);
fclose(fpcommout);
close(ftpcomm_fd);
linkopen = 0;
loggedin = 0;
return(0);
}
int DOquit()
{
int s;
if(linkopen) {
s = DOcommand("QUIT", "");
s = DOclose();
}
printf("FTP done.\n");
exit(0);
}
void donothing(sig)
int sig;
{
}
int DOdata(datacom, file, direction, fd)
char *datacom;
char *file;
int direction; /* RETR or STOR */
int fd;
{
nwio_tcpconf_t tcpconf;
nwio_tcpcl_t tcplopt, tcpcopt;
char *tcp_device;
int ftpdata_fd;
char *buff;
ipaddr_t ripaddr;
tcpport_t rport;
static tcpport_t lport = HTONS(0xF000);
int s;
int i;
int cs;
int pfd[2];
char dummy;
char port[32];
ripaddr = hostip;
rport = HTONS(20);
/* here we set up a connection to listen on if not passive mode */
/* otherwise we use this to connect for passive mode */
if((tcp_device = getenv("TCP_DEVICE")) == NULL)
tcp_device = "/dev/tcp";
if((ftpdata_fd = open(tcp_device, O_RDWR)) < 0) {
perror("ftp: open error on tcp device");
return(-1);
}
if(passive) {
s = DOcommand("PASV", "");
if(s != 227) {
close(ftpdata_fd);
return(s);
}
/* decode host and port */
buff = reply;
while(*buff && (*buff != '(')) buff++;
buff++;
ripaddr = (ipaddr_t)0;
for(i = 0; i < 4; i++) {
ripaddr = (ripaddr << 8) + (ipaddr_t)atoi(buff);
if((buff = strchr(buff, ',')) == (char *)0) {
printf("Could not parse PASV reply\n");
return(-1);
}
buff++;
}
rport = (tcpport_t)atoi(buff);
if((buff = strchr(buff, ',')) == (char *)0) {
printf("Could not parse PASV reply\n");
return(-1);
}
buff++;
rport = (rport << 8) + (tcpport_t)atoi(buff);
ripaddr = ntohl(ripaddr);
rport = ntohs(rport);
}
for (;;) {
tcpconf.nwtc_flags = NWTC_SET_RA | NWTC_SET_RP;
if (passive || ntohs(lport) >= 0xF000) {
tcpconf.nwtc_flags |= NWTC_LP_SEL;
} else {
/* For no good reason Sun hosts don't like it if they have to
* connect to the same port twice in a short time...
*/
lport = htons(ntohs(lport) + 1);
tcpconf.nwtc_flags |= NWTC_LP_SET;
tcpconf.nwtc_locport = lport;
}
tcpconf.nwtc_remaddr = ripaddr;
tcpconf.nwtc_remport = rport;
s = ioctl(ftpdata_fd, NWIOSTCPCONF, &tcpconf);
if(s < 0) {
if (errno == EADDRINUSE) continue;
perror("ftp: ioctl error on NWIOSTCPCONF");
close(ftpdata_fd);
return(s);
}
break;
}
s = ioctl(ftpdata_fd, NWIOGTCPCONF, &tcpconf);
if(s < 0) {
perror("ftp: ioctl error on NWIOGTCPCONF");
close(ftpdata_fd);
return(s);
}
lport = tcpconf.nwtc_locport;
if(passive) {
tcplopt.nwtcl_flags = 0;
s = ioctl(ftpdata_fd, NWIOTCPCONN, &tcpcopt);
if(s < 0) {
perror("ftp: error on ioctl NWIOTCPCONN");
close(ftpdata_fd);
return(0);
}
s = ioctl(ftpdata_fd, NWIOGTCPCONF, &tcpconf);
if(s < 0) {
perror("ftp: error on ioctl NWIOGTCPCONF");
close(ftpdata_fd);
return(0);
}
} else {
tcplopt.nwtcl_flags = 0;
if (pipe(pfd) < 0) {
perror("ftp: could not create a pipe");
return(s);
}
lpid = fork();
if(lpid < 0) {
perror("ftp: could not fork listener");
close(ftpdata_fd);
close(pfd[0]);
close(pfd[1]);
return(s);
} else if(lpid == 0) {
close(pfd[0]);
signal(SIGALRM, donothing);
alarm(15);
close(pfd[1]);
s = ioctl(ftpdata_fd, NWIOTCPLISTEN, &tcplopt);
alarm(0);
if(s < 0)
if(errno == EINTR)
exit(1); /* timed out */
else
exit(-1); /* error */
else
exit(0); /* connection made */
}
/* Wait for the pipe to close, then the listener is ready (almost). */
close(pfd[1]);
(void) read(pfd[0], &dummy, 1);
close(pfd[0]);
while(1) {
signal(SIGALRM, donothing);
alarm(1);
s = ioctl(ftpdata_fd, NWIOGTCPCONF, &tcpconf);
alarm(0);
if(s == -1) break;
}
}
#define hiword(x) ((u16_t)((x) >> 16))
#define loword(x) ((u16_t)(x & 0xffff))
#define hibyte(x) (((x) >> 8) & 0xff)
#define lobyte(x) ((x) & 0xff)
if(!passive) {
sprintf(port, "%u,%u,%u,%u,%u,%u",
hibyte(hiword(ntohl(myip))), lobyte(hiword(ntohl(myip))),
hibyte(loword(ntohl(myip))), lobyte(loword(ntohl(myip))),
hibyte(ntohs(lport)), lobyte(ntohs(lport)));
s = DOcommand("PORT", port);
if(s != 200) {
close(ftpdata_fd);
kill(lpid, SIGKILL);
return(s);
}
}
s = DOcommand(datacom, file);
if(s == 125 || s == 150) {
if(!passive) {
while(1) {
s = wait(&cs);
if(s < 0 || s == lpid)
break;
}
if(s < 0) {
perror("wait error:");
close(ftpdata_fd);
kill(lpid, SIGKILL);
return(s);
}
if((cs & 0x00ff)) {
printf("Child listener failed %04x\n", cs);
close(ftpdata_fd);
return(-1);
}
cs = (cs >> 8) & 0x00ff;
if(cs == 1) {
printf("Child listener timed out\n");
return(DOgetreply());
} else if(cs) {
printf("Child listener returned %02x\n", cs);
close(ftpdata_fd);
return(-1);
}
}
switch(direction) {
case RETR:
s = recvfile(fd, ftpdata_fd);
break;
case STOR:
s = sendfile(fd, ftpdata_fd);
break;
}
close(ftpdata_fd);
s = DOgetreply();
} else {
if(!passive)
kill(lpid, SIGKILL);
close(ftpdata_fd);
}
return(s);
}