Ftpcat v1.0 is a simple program, that allows users to upload and download files and dirlistings from a ftpserver.
c25dbf4b49615bb7763c489be8f641f1cfb5f0b0bde244b4a19f9211c7a81b11
/*
* FTPCAT v1.0
*
* This is the first C++ example i wrote. If you have any comments on it
* please mail me or use the form on my site.
*
* Ftpcat is a simple program, that allows users to upload and download
* files and dirlistings from a ftpserver. Check usage for the commands.
*
* Have fun
*
* -lamagra (access-granted@geocities.com)
* https://lamagra.seKure.de
*/
/* INCLUDES */
#include <stdlib.h>
#include <iostream.h>
#include <stdio.h>
#include <stdarg.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <netdb.h>
#include <arpa/inet.h> // inet_addr()
#include <string.h> // strerror()
#include <ctype.h> // isdigit()
#include <fcntl.h>
/* DEFINES */
#define ANON_PASS "Ftpcat@lamagra.seKure.de"
/* PROTOCOLS + CLASSES */
void error_quit(char *msg,...);
extern int errno;
extern int optind;
extern char *optarg;
char *host, *user,*path;
class ftp
{
int ftpsock;
public:
long port;
int list;
set_default();
connectto(char *host);
login(char *user);
disconnect();
unsigned long resolve(char *host);
sendcmd(char *text, ...);
int get_response();
int get_file();
int put_file();
int dataconn();
};
/* FUNCTIONS */
void error_quit(char *msg,...)
{
va_list va;
va_start(va, msg);
vfprintf(stderr, msg, va);
va_end(va);
exit(-1);
}
usage(char *progname)
{
printf("Ftpcat by lamagra (https://lamagra.seKure.de)\n");
printf(
"Usage: %s [options] user@host:port/path/(file/dir)\n"
"\t port is optional\n"
"\t -h and -?: this text\n"
"\t -l: show dir-contents\n"
"\t -p: put a file\n"
);
exit(0);
}
ftp::set_default()
{
port = 21, list = 0;
}
ftp::connectto(char *host)
{
struct sockaddr_in sin;
sin.sin_addr.s_addr = resolve(host);
sin.sin_port = htons(port);
sin.sin_family = AF_INET;
if((ftpsock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)) == -1)
error_quit("Can't open socket: %s\n",strerror(errno));
if(connect(ftpsock,(struct sockaddr *)&sin,sizeof(struct sockaddr)) == -1)
error_quit("Can't connect to %s.%ld: %s\n",host,port,strerror(errno));
// fcntl(ftpsock,F_SETFL,O_NONBLOCK);
}
ftp::disconnect()
{
sendcmd("QUIT\r\n");
close(ftpsock);
}
ftp::login(char *user)
{
char *passwd;
int gotpass = 0;
if(!strcmp("ftp",user) || !strcmp("anonymous",user))
passwd = ANON_PASS;
else /* Prompt user for password */
passwd = getpass("Please enter password: "),gotpass = 1;
if(get_response() != 220) error_quit("No banner\n");
sendcmd("USER %s\r\n",user);
if(get_response() != 331) error_quit("USER %s failed\n",user);
sendcmd("PASS %s\r\n",passwd);
if(get_response() != 230) error_quit("PASS **** failed\n");
if(gotpass) memset(passwd,0x0,strlen(passwd)); // zero passwd
}
unsigned long ftp::resolve(char *name)
{
struct hostent *hp;
unsigned long ip;
if((ip = inet_addr(name)) == -1)
{
if((hp = gethostbyname(name)) == NULL)
{
printf("Unable to resolve <%s>\n",name);
exit(-1);
}
memcpy(&ip,hp->h_addr,4);
}
return ip;
}
ftp::sendcmd(char *text, ...)
{
va_list va;
char buf[1024];
va_start(va,text);
vsnprintf(buf,1024,text,va);
va_end(va);
if(buf[strlen(buf) - 1] != '\n')
error_quit("Send: text doesn't end with \\n");
if(write(ftpsock, buf, strlen(buf)) == -1)
error_quit("Write error: %s\n",strerror(errno));
}
int ftp::get_response()
{
char response[4];
char tmp;
int i = 0;
while(read(ftpsock,(char *)&tmp,1) == 1)
{
response[i++] = tmp;
if(i > 3)
{
if(response[3] != ' ' || !isdigit(response[0]) || !isdigit(response[1]) || !isdigit(response[2]))
{
while(read(ftpsock,(char *)&tmp,1) == 1 && tmp != '\n');
i = 0;
}
else
{
response[3] = 0x0;
// error_quit("Server send bad response: %s\n",response);
return atoi(response);
}
}
}
}
int ftp::dataconn()
{
int fd;
unsigned int len = sizeof(struct sockaddr);
struct sockaddr_in sin;
char *a, *b;
if((fd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)) == -1)
error_quit("Can't open socket: %s\n",strerror(errno));
/* Get the address from the ftpsock */
if(getsockname(ftpsock,(struct sockaddr *)&sin,&len) == -1)
error_quit("Getsockname failed: %s\n",strerror(errno));
sin.sin_port = 0;
if(bind(fd,(struct sockaddr *)&sin,sizeof(struct sockaddr)) == -1)
error_quit("Can't bind to port: %s",strerror(errno));
if(getsockname(fd,(struct sockaddr *)&sin,&len) == -1)
error_quit("Getsockname failed: %s\n",strerror(errno));
listen(fd,1);
a = (char *)&sin.sin_addr;
b = (char *)&sin.sin_port;
#define UC(x) (((int)x)&0xff)
sendcmd("PORT %d,%d,%d,%d,%d,%d\r\n",
UC(a[0]),UC(a[1]),UC(a[2]),UC(a[3]),
UC(b[0]),UC(b[1]));
if(get_response() != 200) error_quit("PORT failed\n");
sendcmd("TYPE I\r\n");
if(get_response() != 200) error_quit("TYPE failed\n");
return fd;
}
int ftp::get_file()
{
char *file;
struct sockaddr_in sin;
int clientfd;
unsigned int len =sizeof(struct sockaddr);
int fd = dataconn();
if(list) // Get dirlisting
{
sendcmd("CWD %s\r\n",path);
if(get_response() != 250) error_quit("%s doesn't exist\n",path);
sendcmd("LIST -al\r\n");
}
else
{
if((file = (char *)strrchr(path,'/')))
{
*file++ = 0x0;
sendcmd("CWD %s\r\n",path);
if(get_response() != 250) error_quit("%s doesn't exist\n",path);
}else file = path;
sendcmd("RETR %s\r\n",file);
if(get_response() == 550) error_quit ("%s doesn't exist",file);
}
if((clientfd = accept(fd,(struct sockaddr *)&sin,&len)) == -1)
error_quit("Accept() failed: %s\n",strerror(errno));
close(fd);
// fcntl(ftpsock,F_SETFL,O_NONBLOCK);
return clientfd;
}
int ftp::put_file()
{
int fd = dataconn();
struct sockaddr_in sin;
int clientfd;
unsigned int len = sizeof(struct sockaddr);
char *file;
if((file = (char *)strrchr(path,'/')))
{
*file++ = 0x0;
sendcmd("CWD %s\r\n",path);
if(get_response() != 250) error_quit("%s doesn't exist\n",path);
}else file = path;
sendcmd("STOR %s\r\n",file);
if(get_response() == 550) error_quit ("%s doesn't exist",file);
if((clientfd = accept(fd,(struct sockaddr *)&sin,&len)) == -1)
error_quit("Accept() failed: %s\n",strerror(errno));
close(fd);
// fcntl(ftpsock,F_SETFL,O_NONBLOCK);
return clientfd;
}
int ftpdecode(char *string,ftp *obj)
{
char *tmp;
if((tmp = (char *)strchr(string,'/')))
*tmp = 0x0, path = ++tmp;
else return -1;
if((tmp = (char *)strchr(string,':')))
*tmp = 0x0, obj->port = atol(++tmp);
if((tmp = (char *)strchr(string,'@')))
*tmp = 0x0, host = ++tmp;
else return -1;
user = string;
return 0;
}
int main(int argc,char **argv)
{
ftp obj;
char c, buf[1024];
int datafd, len, cmd = 0;
obj.set_default();
while((c = getopt(argc,argv,"h?lp")) != EOF)
{
switch(c)
{
case 'h':
case '?': usage(argv[0]);
break;
case 'l': obj.list = 1;
break;
case 'p': cmd = 1;
break;
case 'd': cmd = 2;
default: error_quit("Unknown option: %c\n",c);
}
}
if((argc - optind) != 1) usage(argv[0]);
if(ftpdecode(argv[optind],&obj) == -1)
error_quit("Bad user@host:port/path string\n");
obj.connectto(host);
obj.login(user);
if(!cmd)
{
datafd = obj.get_file();
while(len = read(datafd,buf,1024))
{
if(len == -1) error_quit("Read() failed: %s\n",strerror(errno));
write(STDOUT_FILENO,buf,len);
memset(buf,0x0,1024);
}
} else
{
datafd = obj.put_file();
printf("[ Ready for datainput ]\n");
while(len = read(STDIN_FILENO,buf,1024))
{
if(len == -1) error_quit("Read() failed: %s\n",strerror(errno));
write(datafd,buf,len);
memset(buf,0x0,1024);
}
}
obj.disconnect();
return 0;
}