04. oktober 2001 - 00:05
#7
OK her er noget hardcore C kode en ftp server.
Sig lige til hvis du heller vil have den på mail
#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <netdb.h>
#include <pthread.h>
#include <stddef.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <pwd.h>
#define YES 0
#define NO 1
#define PASS 2
#define MAX_CONNECTIONS 100
#define RECV_SIZE 1024 //Groesse des recv_buffer
struct client_struct {
int client_no; //Nummer des Clients (1..MAX_CONNECTIONS)
int client_socket; //Socketnummer
pthread_t thread_nr; //Threadnummer
pthread_attr_t thread_attribute; //Attribute des Threads
pthread_t recv_nr; //Threadnummer fuer recv_all_incoming
int is_in_use; //wird er im Moment benutzt?
int logged_in; //schon eingeloggt?
char user[9]; //Username
char *recv_buffer; //Puffer fuer empfangene Daten
char *working_dir; //Zeiger aufs momentane Verzeichnis
int head; //ab hier werden Daten abgelegt
int tail; //bis hierhin werden Daten empfangen
unsigned long int data_ip:32; //IP fuer Datenleitung
unsigned int data_port:16; //Port fuer Datenleitung
unsigned int data_socket; //Socket fuer die Datenleitung
unsigned int passive:8; //Passiver-Modus?
char stru; //Daten-Struktur (F,R)
unsigned int type; //Daten-Type (A,AN,I,L8)
char mode; //Datenübertragungsmodus (S)
struct passwd pass_entry; //Daten des Users
};
char *user_out= \"530 User not logged in\\xd\\xa\";
char *error_in_param=\"501 Syntax error in parameters or arguments\\xd\\xa\";
char *server_root=\"/home/ftp\";
int lauschen;
int lauschen_port=0x2505;
pthread_t local_console_thread;
pthread_attr_t local_console_thread_attr;
struct client_struct incoming_client[MAX_CONNECTIONS]; //hier werden bis zu MAX_CONNECTIONS Andockende Clients abgespeichert
struct sockaddr_in s_in;
void cwd_command(struct client_struct *arg,char *buf);
int get_free_client(void){ //sucht einen freien Platz in dem Clientarray
int i;
for (i=0;i<MAX_CONNECTIONS;i++) if (incoming_client[i].is_in_use==NO) {
incoming_client[i].is_in_use=YES;
return i ;
}
return -1;
}
char *get_command(struct client_struct *arg){ //liefert ein Kommando vom Client
char *command_buf;
int pos,command_size;
pos=arg->head;
if (pos==arg->tail) return NULL; //Warteschlange ist leer
for (pos=arg->head;pos!=arg->tail-2;pos=(pos+1)%RECV_SIZE)
if (arg->recv_buffer[pos]==0x0d) break;
if (arg->recv_buffer[pos+1]==0x0a) {
pos++;
command_size=pos>arg->head?pos-arg->head+1:RECV_SIZE-(arg->head-pos)+1;
printf(\"Command Size %d bytes from client %d\\n\",command_size,arg->client_no);
command_buf=calloc(command_size+1,1);
memcpy(command_buf,arg->recv_buffer+arg->head,command_size);
arg->head+=command_size;
pos=0;
command_buf[command_size]=0;
while ((command_buf[pos]!=32)&&(command_buf[pos]!=0x0d)){
command_buf[pos]=tolower(command_buf[pos]);
pos++;
}
return command_buf;
}
return NULL;
}
void retr_command(struct client_struct *arg,char *buf){ //RETR-Kommando
char *syntax_error=\"500 Syntax error\\xd\\xa\";
int i;
FILE *download;
char *data,*dir;
char *data_out;
int read;
unsigned long size;
struct sockaddr_in s_in;
if (arg->logged_in==NO) return;
for (i=0;i<strlen(buf);i++) if (buf[i]==\' \') break;
i++; //i zeigt auf die Datei
if (i==strlen(buf)) { //keine Datei angegeben
send(arg->client_socket,syntax_error,18,0);
return;
}
dir=calloc(1024,1);
strcat(dir,arg->working_dir);
if (strlen(dir)!=1) strcat(dir,\"/\");
strcat(dir,buf+i);
dir[strlen(dir)-2]=0; //\\xd\\xa abschneiden
download=fopen(dir,\"r\"); //Datei [ffnen;
if (download==NULL){ //Fehler beim [ffnen
switch (errno){
default:
send(arg->client_socket,\"450 Operation not permitted\\xd\\xa\",29,0);
break;
}
free(dir);
return;
}
fseek(download,0,SEEK_END);
size=ftell(download);
fseek(download,0,SEEK_SET);
data=calloc(10*1024,1);
if (data==NULL){
free(dir);
send(arg->client_socket,\"550 Internal Error\\xd\\xa\",20,0);
return;
}
send(arg->client_socket,\"150 Opening Data connection\\xd\\xa\",29,0);
arg->data_socket=socket(AF_INET,SOCK_STREAM,0);
if (arg->data_socket==-1){
free(data);
free(dir);
send(arg->client_socket,\"425 Can not open data connection\\xd\\xa\",32,0);
return;
}
s_in.sin_port=htons(arg->data_port);
s_in.sin_addr.s_addr=htonl(arg->data_ip);
s_in.sin_family=AF_INET;
if (connect(arg->data_socket,(struct sockaddr *)&s_in,sizeof(s_in))==-1){
free(data);
free(dir);
send(arg->client_socket,\"425 Can not open data connection\\xd\\xa\",32,0);
return;
}
if (arg->type==(unsigned int)\'I\'||arg->type==(unsigned int)(\'L\'*256+\'8\')){ //keine Konvertierung nötig
do{
read=fread(data,1,10*1024,download);
if (ferror(download)>0) {
send(arg->client_socket,\"426 Connection abort\\xd\\xa\",22,0);
break;
}
send(arg->data_socket,data,read,0);
} while(!feof(download));
}
else { //\\xd bzw \\xa muß in \\xd\\xa umgewandelt werden
data_out=calloc(10*1024*2,1); //worst-case annehmen
do{
int i;
read=fread(data,1,10*1024,download);
for(i=0;i<read;i++) if (data[i]==\'\\xd\'||data[i]==\'\\xa\') {
data_out[i]=\'\\xd\';
data_out[i+1]=\'\\xa\';
i+=2;
read++;
}
else data_out[i]=data[i];
if (ferror(download)>0) {
send(arg->client_socket,\"426 Connection abort\\xd\\xa\",22,0);
break;
}
send(arg->data_socket,data_out,read,0);
}while(!feof(download));
free(data_out);
}
if (ferror(download)>0) {
free(data);
free(dir);
return;
}
shutdown(arg->data_socket,2);
send(arg->client_socket,\"226 Transfer complete\\xd\\xa\",23,0);
free(data);
free(dir);
return;
}
void stor_command(struct client_struct *arg,char *buf){ //STOR-Kommando
char *syntax_error=\"500 Syntax error\\xd\\xa\";
int i;
FILE *upload;
char *data_in,*dir;
char *data_out;
int write;
unsigned long size;
struct sockaddr_in s_in;
if (arg->logged_in==NO) return;
for (i=0;i<strlen(buf);i++) if (buf[i]==\' \') break;
i++; //i zeigt auf die Datei
if (i==strlen(buf)) { //keine Datei angegeben
send(arg->client_socket,syntax_error,18,0);
return;
}
dir=calloc(1024,1);
strcat(dir,arg->working_dir);
if (strlen(dir)!=1) strcat(dir,\"/\");
strcat(dir,buf+i);
dir[strlen(dir)-2]=0; //\\xd\\xa abschneiden
upload=fopen(dir,\"w\"); //Datei [ffnen;
if (upload==NULL){ //Fehler beim [ffnen
switch (errno){
default:
send(arg->client_socket,\"450 Operation not permitted\\xd\\xa\",29,0);
break;
}
free(dir);
return;
}
data_in=calloc(10*1024,1);
if (data_in==NULL){
free(dir);
send(arg->client_socket,\"550 Internal Error\\xd\\xa\",20,0);
return;
}
send(arg->client_socket,\"150 Opening Data connection\\xd\\xa\",29,0);
arg->data_socket=socket(AF_INET,SOCK_STREAM,0);
if (arg->data_socket==-1){
free(data_in);
free(dir);
send(arg->client_socket,\"425 Can not open data connection\\xd\\xa\",32,0);
return;
}
s_in.sin_port=htons(arg->data_port);
s_in.sin_addr.s_addr=htonl(arg->data_ip);
s_in.sin_family=AF_INET;
if (connect(arg->data_socket,(struct sockaddr *)&s_in,sizeof(s_in))==-1){
free(data_in);
free(dir);
send(arg->client_socket,\"425 Can not open data connection\\xd\\xa\",32,0);
return;
}
if (arg->type==(unsigned int)\'I\'||arg->type==(unsigned int)(\'L\'*256+\'8\')){ //keine Konvertierung nötig
do{
write=recv(arg->data_socket,data_in,10*1024,0);
fwrite(data_in,1,write,upload);
if (ferror(upload)>0) {
send(arg->client_socket,\"426 Connection abort\\xd\\xa\",22,0);
break;
}
} while(write>0);
}
else { //\\xd bzw \\xa muß in \\xd\\xa umgewandelt werden
data_out=calloc(10*1024*2,1); //worst-case annehmen
do{
int i;
write=recv(arg->data_socket,data_in,10*1024,0);
for(i=0;i<write;i++) if (data_in[i]==\'\\xd\' || data_in[i]==\'\\xa\') {
data_out[i]=\'\\xd\';
data_out[i+1]=\'\\xa\';
i+=2;
write++;
}
else data_out[i]=data_in[i];
fwrite(data_out,1,10*1024,upload);
if (ferror(upload)>0) {
send(arg->client_socket,\"426 Connection abort\\xd\\xa\",22,0);
break;
}
}while(write>0);
free(data_out);
}
if (ferror(upload)>0) {
free(data_in);
free(dir);
return;
}
shutdown(arg->data_socket,2);
send(arg->client_socket,\"226 Transfer complete\\xd\\xa\",23,0);
free(data_in);
free(dir);
return;
}
void help(struct client_struct *arg){
char *help_message=\"214-The following commands are recognized:\\xd\\xa CDUP CWD HELP LIST NLST NOOP PASS PORT PWD USER \\xd\\n214 report errors to matthias.kay@itzehoe.netsurf.de\\xd\\xa\";
printf(\"Command HELP from client %d\\n\",arg->client_no);
send(arg->client_socket,help_message,151,0);
printf(\"send help message to client %d\\n\",arg->client_no);
return;
}
void noop_command(struct client_struct *arg, char *buf){ //NOOP-Kommando
char *noop_msg=\"200 OK\\xd\\xa\";
send(arg->client_socket,noop_msg,8,0);
return;
}
int is_dir_ok(struct client_struct *arg, char *dir){ //testet, ob gültiger Zugriff auf Verzeichnis möglich
char *cur_dir;
if (chdir(arg->working_dir)!=0) return NO;
if (chdir(dir)!=0) return NO;
cur_dir=getcwd(NULL,2048);
if (strstr(cur_dir,server_root)==NULL) {
free(cur_dir);
return NO;
}
else if(strstr(cur_dir,server_root)==cur_dir) {
free(cur_dir);
return YES;
}
else {
free(cur_dir);
return NO;
}
return;
}
void cdup_command(struct client_struct *arg, char *buf){
char *buf1;
buf1=calloc(strlen(\"cwd ..\\xd\\xa\")+1,1);
if (buf1==NULL) {
send(arg->client_socket,\"550 Internal Error\\xd\\xa\",20,0);
return;
}
strcpy(buf1,\"cwd ..\\xd\\xa\");
cwd_command(arg,buf1);
free (buf1);
return;
}
void pwd_command(struct client_struct *arg, char *buf){ //PWD-Kommando
char *not_valid=\"501 Working directory is not valid!\\xd\\xa\";
char *buf1;
if(arg->logged_in==NO) {
send(arg->client_socket,user_out,24,0);
return;
}
if (chdir(arg->working_dir)!=0) {
send(arg->client_socket,not_valid,37,0);
return;
}
buf1=calloc(strlen(arg->working_dir)+2,1);
if (buf1==NULL){
send(arg->client_socket,\"550 Internal Error\\xd\\xa\",20,0);
return;
}
strcpy(buf1,arg->working_dir);
strcat(buf1,\"\\xd\\xa\");
send(arg->client_socket,buf1,strlen(buf1),0);
free(buf1);
return;
}
void cwd_command(struct client_struct *arg, char *buf){ //CWD-Kommando
char *cwd_ok=\"250 CWD command ok\\xd\\xa\";
char *no_dir=\"501 Unknown directory\\xd\\xa\";
char *no_perm=\"550 Permission denied\\xd\\xa\";
char *not_entry=\"550 Not a directory\\xd\\xa\";
if(arg->logged_in==NO || strlen(buf)<6) {
send(arg->client_socket,user_out,24,0);
return;
}
buf[strlen(buf)-2]=0; //\\xd\\xa vom Verzeichnisnamen abschneiden
if (is_dir_ok(arg,buf+4)==YES) {
char *test;
chdir(arg->working_dir);
chdir(buf+4);
free(arg->working_dir);
test=getcwd(NULL,2048);
if (test==NULL){
send(arg->client_socket,\"550 Internal Error\\xd\\xa\",20,0);
return;
}
arg->working_dir=test;
send(arg->client_socket,cwd_ok,20,0);
}
else {
switch (errno){
case EACCES:printf(\"CWD: Access to %s not possible for client %d\\n\",buf+4,arg->client_no);
send(arg->client_socket,no_perm,23,0);
break;
default:
case ENOENT:printf(\"CWD: Directory %s does not exist by client %d\\n\",buf+4,arg->client_no);
send(arg->client_socket,no_dir,24,0);
break;
case ENOTDIR:printf(\"CWD: Dir %s is not a directory from client %d\\n\",buf+4,arg->client_no);
send(arg->client_socket,not_entry,21,0);
break;
}
}
return;
}
void list_dir(struct client_struct *arg, char *buf){ //LIST-Kommando
DIR *dp;
struct dirent *ep;
int size;
struct sockaddr_in s_in;
char *command_ok=\"226 Transfer complete\\xd\\xa\";
char *start_trans=\"150 Opening ASCII mode data connection for file list\\xd\\xa\";
char *no_data=\"425 Can not open data connection\\xd\\xa\";
char *no_perm=\"550 Permission denied\\xd\\xa\";
char *no_dir=\"550 Directory does not exist\\xd\\xa\";
char *not_entry=\"550 Not a directory or file\\xd\\xa\";
char *buffer;
struct stat file_info;
if(arg->logged_in==NO) {
send(arg->client_socket,user_out,24,0);
printf(\"LIST Command on client %d user not logged in\\n\",arg->client_no);
arg->passive=NO;
return;
}
printf(\"Command: LIST from client %d\\n\",arg->client_no);
buffer=calloc(1024,1);
for(size=0;buf[size]!=\'\\xd\';size++);
buf[size]=0;
if (buf[4]==\' \') dp=opendir(buf+5);
else dp=opendir(arg->working_dir);
if (dp==NULL || (buf[4]==\' \' && is_dir_ok(arg,buf+5)==NO)){
switch (errno){
case EACCES:printf(\"LIST: Access to %s not possible for client %d\\n\",buf+5,arg->client_no);
send(arg->client_socket,no_perm,23,0);
break;
default:
case ENOENT:printf(\"LIST: Directory %s does not exist by client %d\\n\",buf+5,arg->client_no);
send(arg->client_socket,no_dir,30,0);
break;
case ENOTDIR:printf(\"LIST: Dir %s is not a directory from client %d\\n\",buf+5,arg->client_no);
send(arg->client_socket,not_entry,29,0);
break;
}
free(buffer);
arg->passive=NO;
return;
}
send(arg->client_socket,start_trans,54,0);
if (arg->passive==NO){
arg->data_socket=socket(AF_INET,SOCK_STREAM,0);
if (arg->data_socket==-1){
printf(\"LIST: error in socket() from client %d\\n\",arg->client_no);
send(arg->client_socket,no_data,21,0);
free(buffer);
arg->passive=NO;
return;
}
s_in.sin_addr.s_addr=htonl(arg->data_ip);
s_in.sin_port=htons(arg->data_port);
s_in.sin_family=AF_INET;
if (connect(arg->data_socket,(struct sockaddr *)&s_in,sizeof(s_in))!=0){
printf(\"LIST: No data connection possible to client %d connect()\\n\",arg->client_no);
send(arg->client_socket,no_data,32,0);
shutdown(arg->data_socket,2);
free(buffer);
arg->passive=NO;
printf(\"FEHLER\\n\");
return;
}
}
else { //falls pasv_command abgesetzt
int sock_save;
struct sockaddr sock_addr;
int i=sizeof(sock_addr);
sock_save=accept(arg->data_socket,&sock_addr,&i);
shutdown(arg->data_socket,2);
arg->data_socket=sock_save;
}
if (dp!=NULL){
while (ep=readdir(dp)){
if (lstat(ep->d_name,&file_info)==-1) ;
puts(ep->d_name);
buffer[0]=0;
buffer=strcat(buffer,ctime(&(file_info.st_atime))); //Zeitinfo holen
buffer=strcpy(buffer,buffer+4); //Wochentag entfernen
strcpy(buffer+7,buffer+16); //Uhrzeit entfernen
sprintf(buffer+strlen(buffer)-1,\"%8ld %s\\xd\\xa\",file_info.st_size,ep->d_name);
memmove(buffer+12,buffer,strlen(buffer));
strncpy(buffer,\"---------- \",11);
if (S_ISLNK(file_info.st_mode)) buffer[0]=\'l\';
if (S_ISDIR(file_info.st_mode)) buffer[0]=\'d\';
if (file_info.st_mode & S_IRUSR==S_IRUSR) buffer[1]=\'r\';
if (file_info.st_mode & S_IWUSR==S_IWUSR) buffer[2]=\'w\';
if (file_info.st_mode & S_IXUSR==S_IXUSR) buffer[3]=\'x\';
if (file_info.st_mode & S_IRGRP==S_IRGRP) buffer[4]=\'r\';
if (file_info.st_mode & S_IWGRP==S_IWGRP) buffer[5]=\'w\';
if (file_info.st_mode & S_IXGRP==S_IXGRP) buffer[6]=\'x\';
if (file_info.st_mode & S_IROTH==S_IROTH) buffer[7]=\'r\';
if (file_info.st_mode & S_IWOTH==S_IWOTH) buffer[8]=\'w\';
if (file_info.st_mode & S_IXOTH==S_IXOTH) buffer[9]=\'x\';
send(arg->data_socket,buffer,strlen(buffer),0);
for(size=0;size<1024;size++) buffer[size]=0;
}
closedir(dp);
send(arg->client_socket,command_ok,23,0);
shutdown(arg->data_socket,2);
}
free(buffer);
arg->passive=NO;
return;
}
void name_list(struct client_struct *arg,char *buf){ //NLST-Kommando
DIR *dp;
struct dirent *ep;
int size;
struct sockaddr_in s_in;
char *command_ok=\"226 Transfer complete\\xd\\xa\";
char *start_trans=\"150 Opening ASCII mode data connection for file list\\xd\\xa\";
char *no_data=\"425 Can not open data connection\\xd\\xa\";
char *no_perm=\"550 Permission denied\\xd\\xa\";
char *no_dir=\"550 Directory does not exist\\xd\\xa\";
char *not_entry=\"550 Not a directory or file\\xd\\xa\";
char *buffer;
if(arg->logged_in==NO) {
send(arg->client_socket,user_out,24,0);
printf(\"NLST Command on client %d user not logged in\\n\",arg->client_no);
arg->passive=NO;
return;
}
printf(\"Command: NLST from client %d\\n\",arg->client_no);
buffer=calloc(1024,1);
for(size=0;buf[size]!=\'\\xd\';size++);
buf[size]=0;
if (buf[4]==\' \') dp=opendir(buf+5);
else dp=opendir(arg->working_dir);
if (dp==NULL || (buf[4]==\' \' && is_dir_ok(arg,buf+5)==NO)){
switch (errno){
case EACCES:printf(\"NLST: Access to %s not possible for client %d\\n\",buf+5,arg->client_no);
send(arg->client_socket,no_perm,23,0);
break;
default:
case ENOENT:printf(\"NLST: Directory %s does not exist by client %d\\n\",buf+5,arg->client_no);
send(arg->client_socket,no_dir,30,0);
break;
case ENOTDIR:printf(\"NLST: %s is not a directory from client %d\\n\",buf+5,arg->client_no);
send(arg->client_socket,not_entry,29,0);
break;
}
free(buffer);
arg->passive=NO;
return;
}
send(arg->client_socket,start_trans,54,0);
if (arg->passive==NO){
arg->data_socket=socket(AF_INET,SOCK_STREAM,0);
if (arg->data_socket==-1){
printf(\"NLST: error in socket() from client %d\\n\",arg->client_no);
send(arg->client_socket,no_data,21,0);
free(buffer);
arg->passive=NO;
return;
}
s_in.sin_addr.s_addr=htonl(arg->data_ip);
s_in.sin_port=htons(arg->data_port);
s_in.sin_family=AF_INET;
if (connect(arg->data_socket,(struct sockaddr *)&s_in,sizeof(s_in))!=0){
printf(\"NLST: No data connection possible to client %d connect()\\n\",arg->client_no);
send(arg->client_socket,no_data,32,0);
shutdown(arg->data_socket,2);
free(buffer);
printf(\"FEHLER\\n\");
arg->passive=NO;
return;
}
}
else { //falls pasv_command abgesetzt
int sock_save;
struct sockaddr sock_addr;
int i=sizeof(sock_addr);
sock_save=accept(arg->data_socket,&sock_addr,&i);
shutdown(arg->data_socket,2);
arg->data_socket=sock_save;
}
if (dp!=NULL){
while (ep=readdir(dp)){
sprintf(buffer,\"%s\\xd\\xa\",ep->d_name);
for(size=0;buffer[size]!=0;size++);
send(arg->data_socket,buffer,size,0);
}
closedir(dp);
send(arg->client_socket,command_ok,23,0);
shutdown(arg->data_socket,2);
}
free(buffer);
printf(\"Success\\n\");
arg->passive=NO;
return;
}
void user_login(struct client_struct *arg,char *buf){ //USER Kommando
char *pass_req=\"331 Password required\\xd\\xa\";
struct passwd *p_entry;
char *user_ok= \"230 Username OK, server is ready\\xd\\xa\";
char *user_out=\"501 Username wrong, not logged in\\xd\\xa\";
char *buf1;
int user_length=0;
buf1=calloc(1024,1);
memcpy(buf1,pass_req,26);
while (buf[5+user_length]!=10) user_length++;
if (user_length!=0){
memcpy(buf1+27,buf+5,user_length-1);
buf1[27+user_length+1]=0;
}
if ((user_length==0) || (p_entry=getpwnam(buf1+27))==NULL){
send(arg->client_socket,user_out,35,0);
printf(\"User %s existiert nicht!\\n\",buf1+27);free(buf1);
return;
}
memcpy(&arg->pass_entry,p_entry,sizeof(struct passwd));
strncpy(arg->user+0,buf+27,8);
arg->user[8]=0;
if (arg->pass_entry.pw_passwd==NULL) {
arg->logged_in=YES;
chroot(server_root);
if (setgid(p_entry->pw_gid)==-1){
send(arg->client_socket,\"500 Internal Error\\xd\\xa\",20,0);
return;
}
if (setuid(p_entry->pw_uid)==-1){
send(arg->client_socket,\"500 Internal Error\\xd\\xa\",20,0);
return;
}
send(arg->client_socket,user_ok,34,0);
}
else {
arg->logged_in=PASS;
send(arg->client_socket,pass_req,strlen(pass_req),0);
}
free(buf1);
return;
}
void pass_command(struct client_struct *arg,char *buf){ //PASS-Kommando
char *pass_ok=\"230 Password ok, server is ready\\xd\\xa\";
char *pass_false=\"501 Password wrong\\xd\\xa\";
char *pass_syn=\"500 Syntax error\\xd\\xa\";
char *pass_no=\"501 don\'t need a password\\xd\\xa\";
char *salt,*en_pwd;
if (arg->logged_in==NO){
send(arg->client_socket,user_out,strlen(user_out),0);
return;
}
if (arg->logged_in==YES){ //es wird kein Passwort ben[tigt
send(arg->client_socket,pass_no,strlen(pass_no),0);
return;
}
if (strlen(buf)<7){
send(arg->client_socket,pass_syn,strlen(pass_syn),0);
return;
}
salt=calloc(3,1);
salt[0]=arg->pass_entry.pw_passwd[0];
salt[1]=arg->pass_entry.pw_passwd[1];
en_pwd=crypt(buf+5,salt);
if (strcmp(en_pwd,arg->pass_entry.pw_passwd)!=0) { //PASS ist falsch
send(arg->client_socket,pass_false,strlen(pass_false),0);
free(salt);
return;
}
if (setgid(p_entry->pw_gid)==-1){
send(arg->client_socket,\"500 Internal Error\\xd\\xa\",20,0);
return;
}
if (setuid(p_entry->pw_uid)==-1){
send(arg->client_socket,\"500 Internal Error\\xd\\xa\",20,0);
return;
}
send(arg->client_socket,pass_ok,strlen(pass_ok),0);
chroot(server_root);
free(salt);
return;
}
void port_command(struct client_struct *arg,char *buf){ //PORT Kommando
int i,j,k;
unsigned int port;
char *command_ok=\"200 PORT command ok\\xd\\xa\";
if(arg->logged_in==NO) {
send(arg->client_socket,user_out,24,0);
return;
}
k=j=0;
for (i=0;buf[i]!=0;i++) if (buf[i]==\',\') { //alle \',\' durch \'.\' ersetzen
buf[i]=\'.\';
k++;
if (k==4){ //ab hier beginnt der Port
port=atoi(buf+i+1)*256; //das erste Byte
for(j=i+1;buf[j]!=\',\';j++); //das zweite Byte suchen
port+=atoi(buf+j+1);
buf[i]=\' \'; //trennt IP von Port
}
}
if (k!=5){ //das waren zu wenig/viel Parameter
send(arg->client_socket,error_in_param,45,0);
return;
}
for (i=0;buf[i]!=0 && buf[i]!=\' \';i++); //ersten Parameter suchen (IP)
i++;
if ((arg->data_ip=ntohl(inet_addr(buf+i)))==-1){ //Adresse fuer Datenleitung ermitteln
send(arg->client_socket,error_in_param,45,0);
return;
}
arg->data_port=port; //neuer Port wurde berechnet
send(arg->client_socket,command_ok,21,0);
return;
}
void syst_command(struct client_struct *arg,char *buf){ //SYST-Kommando
send(arg->client_socket,\"215 UNIX\\xd\\xa\",strlen(\"215 UNIX\\xd\\xa\"),0);
return;
}
void recv_all_incoming(struct client_struct *arg){
char *buf;
int pos,rest_size,count;
buf=calloc(RECV_SIZE,1);
for (;;){
rest_size=arg->head-arg->tail;
if (rest_size>0) rest_size--;
else rest_size+=RECV_SIZE-1;
pos=0;
count=recv(arg->client_socket,buf,rest_size,0); //soviele Daten empfangen, wie noch Platz im Puffer
printf(\"received %d bytes from client %d\\n\",count,arg->client_no);
if (count==0) { //Client hat Verbindung unterbrochen\'
printf(\"recv_all_incoming(): client closed connection client %d\\n\",arg->client_no);
free(buf);
pthread_exit(NULL);
return;
}
while (count>0) {
arg->recv_buffer[arg->tail]=buf[pos];
arg->tail=(arg->tail+1)%RECV_SIZE;
pos++;
count--;
}
}
free(buf);
return;
}
void pasv_command(struct client_struct *arg,char *buf){ //PASV-Kommando
char *pasv_1=\"227 Entering Passiv Mode (\";
char *pasv_3=\")\\xd\\xa\";
char *pasv_2,*pasv_ok;
int i,sock_save;
struct sockaddr_in sock_in;
struct sockaddr sock_addr;
int addr_size=sizeof(sock_addr);
(arg->data_port)++; //hier wartet der Server auf eine Datenverbindung
pasv_ok=calloc(1024,1);
strcpy(pasv_ok,pasv_1);
pasv_2=inet_ntoa(htonl(arg->data_ip));
strcat(pasv_ok,pasv_2);
strcat(pasv_ok,\",\");
sprintf(pasv_ok+strlen(pasv_ok),\"%d,\",arg->data_port/256);
sprintf(pasv_ok+strlen(pasv_ok),\"%d\",arg->data_port%256);
strcat(pasv_ok,pasv_3);
for(i=0;i<strlen(pasv_ok);i++) if (pasv_ok[i]==\'.\') pasv_ok[i]=\',\';
arg->passive=YES;
arg->data_socket=socket(AF_INET,SOCK_STREAM,0);
if (arg->data_socket==-1) puts(\"Socket Error\");
sock_in.sin_family=AF_INET;
sock_in.sin_port=htons(arg->data_port);
sock_in.sin_addr.s_addr=inet_addr(\"127.0.0.1\"); //htonl(arg->data_ip);
if (arg->data_socket==-1) puts(\"Socket Error\");
if (bind(arg->data_socket,(struct sockaddr *)&sock_in,sizeof(sock_in))==-1){
send(arg->client_socket,\"550 Internal Error\\xd\\xa\",20,0);
puts(\"Bind-Error\");
return;
}
if (listen(arg->data_socket,1)==-1) puts(\"Error-Listen\");
send(arg->client_socket,pasv_ok,strlen(pasv_ok),0);
free(pasv_ok);
return;
}
void stru_command(struct client_struct *arg,char *buf){ //STRU-Kommando
char c;
if (strlen(buf)!=8){ //Es wurde zuviel/zuwenig angegeben
send(arg->client_socket,\"500 Syntax error\\xd\\xa\",18,0);
return;
}
c=toupper(buf[strlen(buf)-1-2]); //Strukturtyp holen
if (c!=\'F\'&&c!=\'R\'&&c!=\'P\'){
send(arg->client_socket,\"501 Unknown structure\\xd\\xa\",23,0);
return;
}
if (c==\'P\' || c==\'R\'){
send(arg->client_socket,\"504 Structure unavailable\\xd\\xa\",27,0);
return;
}
arg->stru=c;
send(arg->client_socket,\"200 Command OK\\xd\\xa\",16,0);
return;
}
void mode_command(struct client_struct *arg,char *buf){ //MODE-Kommando
char c;
if (strlen(buf)!=8){ //Es wurde zuviel/zuwenig angegeben
send(arg->client_socket,\"500 Syntax error\\xd\\xa\",18,0);
return;
}
c=toupper(buf[strlen(buf)-1-2]); //Modustyp holen
if (c!=\'B\'&&c!=\'C\'&&c!=\'S\'){
send(arg->client_socket,\"501 Unknown mode\\xd\\xa\",18,0);
return;
}
if (c==\'C\'){
send(arg->client_socket,\"504 Modus unavailable\\xd\\xa\",23,0);
return;
}
arg->mode=c;
send(arg->client_socket,\"200 Command OK\\xd\\xa\",16,0);
return;
}
void type_command(struct client_struct *arg,char *buf){ //TYPE-Kommando
#define AN (unsigned int)(\'A\'*256+\'N\')
#define L8 (unsigned int)(\'L\'*256+\'8\')
unsigned int c;
if (strlen(buf)!=8 && strlen(buf)!=9){ //Es wurde zuviel/zuwenig angegeben
send(arg->client_socket,\"500 Syntax error\\xd\\xa\",18,0);
return;
}
if (strlen(buf)==8) c=(unsigned int) toupper(buf[strlen(buf)-1-2]);
else c=(unsigned int) (toupper(buf[strlen(buf)-1-3])*256+toupper(buf[strlen(buf)-1-2]));
if (arg->type!=(unsigned int)\'A\' && arg->type!=(unsigned int)\'I\' && arg->type!=L8 && arg->type!=AN){
send(arg->client_socket,\"501 Unknown type\\xd\\xa\",18,0);
return;
}
arg->type=c;
if (arg->type==(unsigned int)\'A\') send(arg->client_socket,\"200 Command ok, but TYPE A is TYPE AN!\\xd\\xa\",40,0);
else send(arg->client_socket,\"200 Command OK\\xd\\xa\",16,0);
return;
#undef AN
#undef L8
}
void handle_incoming(struct client_struct *arg){ //hier werden die Clients bedient
char *actual_command;
char *welcome_message=\"220 FTP-Server V1.0 is ready (written by Matthias Kay 1997)\\xd\\xa\";
send(arg->client_socket,welcome_message,61,0); //Welcome message senden
printf(\"send welcome_message to client %d\\n\",arg->client_no);
pthread_create(&arg->recv_nr,&local_console_thread_attr,(void *)recv_all_incoming,arg);
actual_command=calloc(1,1); //wegen free(actual_command)
do {
do {
free(actual_command);
while ((actual_command=get_command(arg))==NULL) ;
printf(\"%s\",actual_command);
if (strncmp(\"help\",actual_command,4)==0) help(arg);
else if (strncmp(\"user\",actual_command,4)==0) user_login(arg,actual_command);
else if (strncmp(\"port\",actual_command,4)==0) port_command(arg,actual_command);
else if (strncmp(\"nlst\",actual_command,4)==0) name_list(arg,actual_command);
else if (strncmp(\"list\",actual_command,4)==0) list_dir(arg,actual_command);
else if (strncmp(\"cwd\",actual_command,3)==0) cwd_command(arg,actual_command);
else if (strncmp(\"pwd\",actual_command,3)==0) pwd_command(arg,actual_command);
else if (strncmp(\"cdup\",actual_command,4)==0) cdup_command(arg,actual_command);
else if (strncmp(\"noop\",actual_command,4)==0) noop_command(arg,actual_command);
else if (strncmp(\"syst\",actual_command,4)==0) syst_command(arg,actual_command);
else if (strncmp(\"pasv\",actual_command,4)==0) pasv_command(arg,actual_command);
else if (strncmp(\"retr\",actual_command,4)==0) retr_command(arg,actual_command);
else if (strncmp(\"type\",actual_command,4)==0) type_command(arg,actual_command);
else if (strncmp(\"mode\",actual_command,4)==0) mode_command(arg,actual_command);
else if (strncmp(\"stru\",actual_command,4)==0) stru_command(arg,actual_command);
else if (strncmp(\"pass\",actual_command,4)==0) pass_command(arg,actual_command);
else if (strncmp(\"stor\",actual_command,4)==0) stor_command(arg,actual_command);
}while (strncmp(\"quit\",actual_command,4)!=0 && strncmp(\"rein\",actual_command,4)!=0);
//hier den \"rein\"-Befehl einfügen!!
} while (strncmp(\"quit\",actual_command,4)!=0);
send(arg->client_socket,\"221 Goodbye\\xd\\xa\",13,0);
shutdown(arg->client_socket,2);
return;
}
int main () {
int dummy_size,i,next_client; //Nummer von n]chsten freien Client
for (i=0;i<MAX_CONNECTIONS;i++) {
incoming_client[i].is_in_use=NO; //alle Clients als unbenutzt markieren
incoming_client[i].logged_in=NO;
incoming_client[i].client_no=i;
incoming_client[i].data_port=htons(20);
incoming_client[i].working_dir=server_root;
incoming_client[i].passive=NO;
incoming_client[i].stru=\'F\';
incoming_client[i].mode=\'S\';
incoming_client[i].type=(unsigned int) (\'A\'*256+\'N\');
}
printf(\"FTP-SERVER (c)1997 Matthias Kay\\n\");
lauschen=socket(AF_INET,SOCK_STREAM,0);
if (lauschen==-1) {
printf(\"FTP: Fehler beim Erstellen des Sockets!\\n\");
printf(\"%d\",errno);
exit(1);
}
s_in.sin_port=htons(lauschen_port);
s_in.sin_addr.s_addr=inet_addr(\"127.0.0.1\");
s_in.sin_family=AF_INET;
if (bind(lauschen,(struct sockaddr *)&s_in,sizeof(s_in))==-1) {
printf(\"FTP: Bind-Error!\\n\");
printf(\"%d\",errno);
exit(1);
}
if (listen(lauschen,5)==-1) {
printf(\"FTP: Listen-Error!\\n\");
printf(\"%d\",errno);
exit(1);
}
for (;;){
while ((next_client=get_free_client())==-1) ; //bis ein freier gefunden wurde
dummy_size=sizeof(s_in);
incoming_client[next_client].client_socket=accept(lauschen,(struct sockaddr*)&s_in,&dummy_size);
printf(\"FTP: Verbunden mit %x: %d\\n\",s_in.sin_addr,s_in.sin_port);
pthread_attr_init(&incoming_client[next_client].thread_attribute);
incoming_client[next_client].thread_attribute.detachstate=PTHREAD_CREATE_DETACHED;
incoming_client[next_client].recv_buffer=calloc(RECV_SIZE,1);
incoming_client[next_client].head=0;
incoming_client[next_client].tail=0;
incoming_client[next_client].data_ip=ntohl(s_in.sin_addr.s_addr);
pthread_create(&incoming_client[next_client].thread_nr,&incoming_client[next_client].thread_attribute,(void *)handle_incoming,&incoming_client[next_client]);
}
printf(\"Socket geschlossen\\n\");
shutdown(lauschen,2);
return 0;
}