More work on ftp server
This commit is contained in:
parent
c304f02496
commit
d9d0b6f89e
@ -2,13 +2,41 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <openssl/sha.h>
|
#include <openssl/sha.h>
|
||||||
|
#include <sqlite3.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/select.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <errno.h>
|
||||||
#include "magiftpd.h"
|
#include "magiftpd.h"
|
||||||
#include "../../inih/ini.h"
|
#include "../../inih/ini.h"
|
||||||
|
|
||||||
static struct ftpclient **clients;
|
static struct ftpclient **clients;
|
||||||
static int client_count = 0;
|
static int client_count = 0;
|
||||||
|
|
||||||
static int handler(void* user, const char* section, const char* name, const char* value) {}
|
struct dllist {
|
||||||
|
char *data;
|
||||||
|
struct dllist *prev;
|
||||||
|
struct dllist *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
void sigchld_handler(int s)
|
||||||
|
{
|
||||||
|
// waitpid() might overwrite errno, so we save and restore it:
|
||||||
|
int saved_errno = errno;
|
||||||
|
|
||||||
|
while(waitpid(-1, NULL, WNOHANG) > 0);
|
||||||
|
|
||||||
|
errno = saved_errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int handler(void* user, const char* section, const char* name, const char* value) {
|
||||||
struct ftpserver *cfg = (struct ftpserver *)user;
|
struct ftpserver *cfg = (struct ftpserver *)user;
|
||||||
|
|
||||||
if (strcasecmp(section, "main") == 0) {
|
if (strcasecmp(section, "main") == 0) {
|
||||||
@ -18,6 +46,9 @@ static int handler(void* user, const char* section, const char* name, const char
|
|||||||
cfg->userdb = strdup(value);
|
cfg->userdb = strdup(value);
|
||||||
} else if (strcasecmp(name, "file root") == 0) {
|
} else if (strcasecmp(name, "file root") == 0) {
|
||||||
cfg->fileroot = strdup(value);
|
cfg->fileroot = strdup(value);
|
||||||
|
if (cfg->fileroot[strlen(cfg->fileroot) -1] == '/') {
|
||||||
|
cfg->fileroot[strlen(cfg->fileroot) -1] = '\0';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
@ -50,16 +81,312 @@ char *hash_sha256(char *pass, char *salt) {
|
|||||||
return shash;
|
return shash;
|
||||||
}
|
}
|
||||||
|
|
||||||
int send_msg(struct ftpclient *client, char *msg) {
|
void send_data(struct ftpclient *client, char *msg, int len) {
|
||||||
|
int n = 0;
|
||||||
|
|
||||||
|
while (len > 0) {
|
||||||
|
n = send(client->data_socket, msg + n, len, 0);
|
||||||
|
len -= n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void send_msg(struct ftpclient *client, char *msg) {
|
||||||
int len = strlen(msg);
|
int len = strlen(msg);
|
||||||
int n = 0;
|
int n = 0;
|
||||||
|
|
||||||
while (l > 0) {
|
while (len > 0) {
|
||||||
n = send(client->fd, msg + n, l, 0);
|
n = send(client->fd, msg + n, len, 0);
|
||||||
l -= n;
|
len -= n;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void close_tcp_connection(struct ftpclient* client) {
|
||||||
|
if (client->data_srv_socket > 0) {
|
||||||
|
close(client->data_srv_socket);
|
||||||
|
client->data_srv_socket = -1;
|
||||||
|
}
|
||||||
|
if (client->data_socket > 0) {
|
||||||
|
close(client->data_socket);
|
||||||
|
client->data_socket = -1;
|
||||||
|
}
|
||||||
|
if (strlen(client->data_ip) > 0) {
|
||||||
|
memset(client->data_ip, 0, 20);
|
||||||
|
client->data_port = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int open_tcp_connection(struct ftpserver *cfg, struct ftpclient *client) {
|
||||||
|
if (strlen(client->data_ip) != 0) {
|
||||||
|
client->data_socket = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
struct sockaddr_in servaddr;
|
||||||
|
servaddr.sin_family = AF_INET;
|
||||||
|
servaddr.sin_port = htons(client->data_port);
|
||||||
|
if (inet_aton(client->data_ip, &(servaddr.sin_addr)) <= 0) {
|
||||||
|
fprintf(stderr, "Error in port command\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (connect(client->data_socket, (struct sockaddr *) &servaddr, sizeof(struct sockaddr)) == -1) {
|
||||||
|
fprintf(stderr, "Error connecting to client\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else if (client->data_srv_socket != 0) {
|
||||||
|
socklen_t sock = sizeof(struct sockaddr);
|
||||||
|
struct sockaddr_in data_client;
|
||||||
|
client->data_socket = accept(client->data_srv_socket, (struct sockaddr*) &data_client, &sock);
|
||||||
|
|
||||||
|
if (client->data_socket < 0) {
|
||||||
|
fprintf(stderr, "Accept Error\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void handle_PASV(struct ftpserver *cfg, struct ftpclient *client) {
|
||||||
|
char buffer[200];
|
||||||
|
char *ipcpy;
|
||||||
|
char *ipptr;
|
||||||
|
if (client->data_socket > 0) {
|
||||||
|
close(client->data_socket);
|
||||||
|
client->data_socket = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (client->data_srv_socket > 0) {
|
||||||
|
close(client->data_srv_socket);
|
||||||
|
}
|
||||||
|
|
||||||
|
client->data_srv_socket = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
if (client->data_srv_socket < 0) {
|
||||||
|
send_msg(client, "426 PASV failure.\r\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
struct sockaddr_in server;
|
||||||
|
server.sin_family = AF_INET;
|
||||||
|
server.sin_addr.s_addr = inet_addr(client->ip);
|
||||||
|
server.sin_port = htons(0);
|
||||||
|
|
||||||
|
if (bind(client->data_srv_socket, (struct sockaddr*) &server, sizeof(struct sockaddr)) < 0) {
|
||||||
|
send_msg(client, "426 PASV failure\r\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (listen(client->data_srv_socket, 1) < 0) {
|
||||||
|
send_msg(client, "426 PASV failure\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sockaddr_in file_addr;
|
||||||
|
socklen_t file_sock_len = sizeof(struct sockaddr);
|
||||||
|
getsockname(client->data_srv_socket, (struct sockaddr*) &file_addr, &file_sock_len);
|
||||||
|
int port = ntohs(file_addr.sin_port);
|
||||||
|
|
||||||
|
ipcpy = strdup(client->ip);
|
||||||
|
|
||||||
|
ipptr = strtok(ipcpy, ".");
|
||||||
|
|
||||||
|
strcpy(buffer, "227 Entering Passive Mode (");
|
||||||
|
|
||||||
|
while (ipptr != NULL) {
|
||||||
|
sprintf(buffer, "%s%s,", buffer, ipptr);
|
||||||
|
ipptr = strtok(NULL, ".");
|
||||||
|
}
|
||||||
|
|
||||||
|
sprintf(buffer, "%s%d,%d)\r\n", buffer, port / 256, port % 256);
|
||||||
|
|
||||||
|
send_msg(client, buffer);
|
||||||
|
free(ipcpy);
|
||||||
|
}
|
||||||
|
|
||||||
|
void handle_RETR(struct ftpserver *cfg, struct ftpclient *client, char *file) {
|
||||||
|
char newpath[PATH_MAX];
|
||||||
|
FILE *fptr;
|
||||||
|
char buffer[1024];
|
||||||
|
snprintf(newpath, PATH_MAX, "%s/%s/%s", cfg->fileroot, client->current_path, file);
|
||||||
|
struct stat s;
|
||||||
|
pid_t pid = fork();
|
||||||
|
int n;
|
||||||
|
|
||||||
|
if (pid > 0) {
|
||||||
|
// nothing
|
||||||
|
} else if (pid == 0) {
|
||||||
|
|
||||||
|
if (stat(newpath, &s) == 0) {
|
||||||
|
if (!S_ISDIR(s.st_mode)) {
|
||||||
|
fptr = fopen(newpath, "rb");
|
||||||
|
if (fptr) {
|
||||||
|
if (open_tcp_connection(cfg, client)) {
|
||||||
|
send_msg(client, "150 Data connection accepted; transfer starting.\r\n");
|
||||||
|
do {
|
||||||
|
n = fread(buffer, 1, 1024, fptr);
|
||||||
|
send_data(client, buffer, n);
|
||||||
|
} while (n == 1024);
|
||||||
|
fclose(fptr);
|
||||||
|
close_tcp_connection(client);
|
||||||
|
send_msg(client, "226 Transfer OK.\r\n");
|
||||||
|
exit(0);
|
||||||
|
} else {
|
||||||
|
send_msg(client, "425 TCP connection cannot be established.\r\n");
|
||||||
|
fclose(fptr);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
send_msg(client, "451 RETR Failed\r\n");
|
||||||
|
exit(0);
|
||||||
|
} else {
|
||||||
|
send_msg(client, "451 RETR Failed.\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void handle_LIST(struct ftpserver *cfg, struct ftpclient *client) {
|
||||||
|
char newpath[PATH_MAX];
|
||||||
|
DIR *dirp;
|
||||||
|
struct dirent *dp;
|
||||||
|
char linebuffer[256];
|
||||||
|
snprintf(newpath, PATH_MAX, "%s/%s", cfg->fileroot, client->current_path);
|
||||||
|
struct stat s;
|
||||||
|
pid_t pid = fork();
|
||||||
|
|
||||||
|
if (pid > 0) {
|
||||||
|
// nothing
|
||||||
|
} else if (pid == 0) {
|
||||||
|
dirp = opendir(newpath);
|
||||||
|
|
||||||
|
if (!dirp) {
|
||||||
|
send_msg(client, "451 Could not read directory.\r\n");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!open_tcp_connection(cfg, client)) {
|
||||||
|
send_msg(client, "425 TCP connection cannot be established.\r\n");
|
||||||
|
closedir(dirp);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
send_msg(client, "150 Data connection accepted; transfer starting.\r\n");
|
||||||
|
while ((dp = readdir(dirp)) != NULL) {
|
||||||
|
snprintf(newpath, PATH_MAX, "%s/%s/%s", cfg->fileroot, client->current_path, dp->d_name);
|
||||||
|
if (stat(newpath, &s) == 0) {
|
||||||
|
snprintf(linebuffer, 256, "%s%c\r\n", dp->d_name, (S_ISDIR(s.st_mode) ? '/' : ' '));
|
||||||
|
send_data(client, linebuffer, strlen(linebuffer));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
closedir(dirp);
|
||||||
|
close_tcp_connection(client);
|
||||||
|
send_msg(client, "226 Transfer ok.\r\n");
|
||||||
|
exit(0);
|
||||||
|
} else {
|
||||||
|
send_msg(client, "451 Could not read directory.\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void handle_PORT(struct ftpserver *cfg, struct ftpclient *client, char *arg) {
|
||||||
|
if (client->data_socket > 0) {
|
||||||
|
close(client->data_socket);
|
||||||
|
}
|
||||||
|
int a,b,c,d,e,f;
|
||||||
|
|
||||||
|
sscanf(arg, "%d,%d,%d,%d,%d,%d", &a, &b, &c, &d, &e, &f);
|
||||||
|
sprintf(client->data_ip, "%d.%d.%d.%d", a, b, c, d);
|
||||||
|
client->data_port = e * 256 + f;
|
||||||
|
send_msg(client, "200 PORT command successful.\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void handle_CWD(struct ftpserver *cfg, struct ftpclient *client, char *dir) {
|
||||||
|
struct dllist *proot;
|
||||||
|
struct dllist *pptr;
|
||||||
|
char *rescpy;
|
||||||
|
char *ptr;
|
||||||
|
char newpath[PATH_MAX];
|
||||||
|
struct stat s;
|
||||||
|
|
||||||
|
proot = (struct dllist *)malloc(sizeof(struct dllist));
|
||||||
|
|
||||||
|
if (!proot) {
|
||||||
|
fprintf(stderr, "Out of memory\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
proot->next = NULL;
|
||||||
|
proot->prev = NULL;
|
||||||
|
proot->data = NULL;
|
||||||
|
|
||||||
|
pptr = proot;
|
||||||
|
|
||||||
|
if (dir[0] == '/') {
|
||||||
|
rescpy = strdup(dir);
|
||||||
|
} else {
|
||||||
|
rescpy = (char *)malloc(strlen(dir) + strlen(client->current_path) + 2);
|
||||||
|
if (!rescpy) {
|
||||||
|
fprintf(stderr, "Out of memory\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
sprintf(rescpy, "%s/%s", client->current_path, dir);
|
||||||
|
}
|
||||||
|
ptr = strtok(rescpy, "/");
|
||||||
|
|
||||||
|
while (ptr != NULL) {
|
||||||
|
if (strcmp(ptr, "..") == 0) {
|
||||||
|
if (pptr->prev != NULL) {
|
||||||
|
pptr = pptr->prev;
|
||||||
|
free(pptr->next);
|
||||||
|
pptr->next = NULL;
|
||||||
|
}
|
||||||
|
} else if (strcmp(ptr, ".") != 0) {
|
||||||
|
pptr->data = ptr;
|
||||||
|
pptr->next = (struct dllist *)malloc(sizeof(struct dllist));
|
||||||
|
if (!pptr->next) {
|
||||||
|
fprintf(stderr, "Out of memory\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
pptr->next->data = NULL;
|
||||||
|
pptr->next->prev = pptr;
|
||||||
|
pptr->next->next = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr = strtok(NULL, "/");
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy(newpath, cfg->fileroot);
|
||||||
|
|
||||||
|
pptr = proot;
|
||||||
|
|
||||||
|
while (pptr != NULL && pptr->data != NULL) {
|
||||||
|
snprintf(newpath, PATH_MAX, "%s/%s", newpath, pptr->data);
|
||||||
|
pptr = pptr->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stat(newpath, &s) == 0) {
|
||||||
|
if (S_ISDIR(s.st_mode)) {
|
||||||
|
pptr = proot;
|
||||||
|
client->current_path[0] = '\0';
|
||||||
|
while (pptr != NULL && pptr->data != NULL) {
|
||||||
|
snprintf(client->current_path, PATH_MAX, "%s/%s", client->current_path, pptr->data);
|
||||||
|
pptr = pptr->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
send_msg(client, "250 Okay.\r\n");
|
||||||
|
} else {
|
||||||
|
send_msg(client, "550 No such file or directory.\r\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
send_msg(client, "550 No such file or directory.\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
pptr = proot;
|
||||||
|
|
||||||
|
while (pptr != NULL) {
|
||||||
|
if (pptr->next != NULL) {
|
||||||
|
pptr = pptr->next;
|
||||||
|
free(pptr->prev);
|
||||||
|
} else {
|
||||||
|
free(pptr);
|
||||||
|
pptr = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(rescpy);
|
||||||
|
}
|
||||||
|
|
||||||
void handle_TYPE(struct ftpserver *cfg, struct ftpclient *client) {
|
void handle_TYPE(struct ftpserver *cfg, struct ftpclient *client) {
|
||||||
send_msg(client, "200 Type set to I.\r\n");
|
send_msg(client, "200 Type set to I.\r\n");
|
||||||
}
|
}
|
||||||
@ -92,9 +419,10 @@ void handle_PASS(struct ftpserver *cfg, struct ftpclient *client, char *password
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(client->name, "anonymous")) {
|
if (strcmp(client->name, "anonymous") == 0) {
|
||||||
strncpy(client->password, password, 32);
|
strncpy(client->password, password, 32);
|
||||||
client->password[31] = '\0';
|
client->password[31] = '\0';
|
||||||
|
send_msg(client, "230 User Logged in, Proceed.\r\n");
|
||||||
} else {
|
} else {
|
||||||
rc = sqlite3_open(cfg->userdb, &db);
|
rc = sqlite3_open(cfg->userdb, &db);
|
||||||
if (rc != SQLITE_OK) {
|
if (rc != SQLITE_OK) {
|
||||||
@ -106,7 +434,7 @@ void handle_PASS(struct ftpserver *cfg, struct ftpclient *client, char *password
|
|||||||
if (rc == SQLITE_OK) {
|
if (rc == SQLITE_OK) {
|
||||||
sqlite3_bind_text(res, 1, client->name, -1, 0);
|
sqlite3_bind_text(res, 1, client->name, -1, 0);
|
||||||
} else {
|
} else {
|
||||||
fprintf(sterr, "Failed to execute statement: %s", sqlite3_errmsg(db));
|
fprintf(stderr, "Failed to execute statement: %s", sqlite3_errmsg(db));
|
||||||
sqlite3_close(db);
|
sqlite3_close(db);
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
@ -114,8 +442,8 @@ void handle_PASS(struct ftpserver *cfg, struct ftpclient *client, char *password
|
|||||||
int step = sqlite3_step(res);
|
int step = sqlite3_step(res);
|
||||||
|
|
||||||
if (step == SQLITE_ROW) {
|
if (step == SQLITE_ROW) {
|
||||||
pass_hash = hash_sha256(password, sqlite3_column_text(res, 1));
|
pass_hash = hash_sha256(password, (char *)sqlite3_column_text(res, 1));
|
||||||
if (strcmp(pass_hash, sqlite3_column_text(res, 0)) == 0) {
|
if (strcmp(pass_hash, (char *)sqlite3_column_text(res, 0)) == 0) {
|
||||||
send_msg(client, "230 User Logged in, Proceed.\r\n");
|
send_msg(client, "230 User Logged in, Proceed.\r\n");
|
||||||
strncpy(client->password, password, 32);
|
strncpy(client->password, password, 32);
|
||||||
} else {
|
} else {
|
||||||
@ -135,12 +463,13 @@ void handle_PASS(struct ftpserver *cfg, struct ftpclient *client, char *password
|
|||||||
}
|
}
|
||||||
|
|
||||||
void handle_USER(struct ftpserver *cfg, struct ftpclient *client, char *username) {
|
void handle_USER(struct ftpserver *cfg, struct ftpclient *client, char *username) {
|
||||||
strncpy(client->name, username, 16)
|
fprintf(stderr, "username %s\n", username);
|
||||||
|
strncpy(client->name, username, 16);
|
||||||
client->name[15] = '\0';
|
client->name[15] = '\0';
|
||||||
if (strcmp(client->name, "anonymous") == 0) {
|
if (strcmp(client->name, "anonymous") == 0) {
|
||||||
send_msg(client, "331 Guest login ok, send your complete e-mail address as password.\r\n");
|
send_msg(client, "331 Guest login ok, send your complete e-mail address as password.\r\n");
|
||||||
} else {
|
} else {
|
||||||
send_msg(client, "331 User name ok, need password.\r\n")
|
send_msg(client, "331 User name ok, need password.\r\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,6 +482,14 @@ int handle_client(struct ftpserver *cfg, struct ftpclient *client, char *buf, in
|
|||||||
int argument_len = 0;
|
int argument_len = 0;
|
||||||
int stage = 0;
|
int stage = 0;
|
||||||
|
|
||||||
|
memset(cmd, 0, 1024);
|
||||||
|
memset(argument, 0, 1024);
|
||||||
|
|
||||||
|
while (buf[nbytes-1] == '\r' || buf[nbytes-1] == '\n') {
|
||||||
|
buf[nbytes-1] = '\0';
|
||||||
|
nbytes--;
|
||||||
|
}
|
||||||
|
|
||||||
for (i=0;i<nbytes;i++) {
|
for (i=0;i<nbytes;i++) {
|
||||||
if (stage == 0 && buf[i] != ' ') {
|
if (stage == 0 && buf[i] != ' ') {
|
||||||
cmd[cmd_len++] = buf[i];
|
cmd[cmd_len++] = buf[i];
|
||||||
@ -165,35 +502,50 @@ int handle_client(struct ftpserver *cfg, struct ftpclient *client, char *buf, in
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "Command: %s, Argument: %s\n", cmd, argument);
|
||||||
|
|
||||||
if (strcmp(cmd, "USER") == 0) {
|
if (strcmp(cmd, "USER") == 0) {
|
||||||
if (argument_len > 0) {
|
if (argument_len > 0) {
|
||||||
handle_USER(cfg, client, argument);
|
handle_USER(cfg, client, argument);
|
||||||
} else {
|
} else {
|
||||||
send_msg(client, "530 Missing username.\r\n")
|
send_msg(client, "530 Missing username.\r\n");
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
if (strcmp(cmd, "PASS") == 0) {
|
if (strcmp(cmd, "PASS") == 0) {
|
||||||
if (argument_len > 0) {
|
if (argument_len > 0) {
|
||||||
handle_PASS(cfg, client, argument);
|
handle_PASS(cfg, client, argument);
|
||||||
} else {
|
} else {
|
||||||
send_msg(client, "530 Username or Password not accepted.\r\n")
|
send_msg(client, "530 Username or Password not accepted.\r\n");
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
if (strcmp(cmd, "SYST") == 0) {
|
if (strcmp(cmd, "SYST") == 0) {
|
||||||
handle_SYST(cfg, client);
|
handle_SYST(cfg, client);
|
||||||
} else
|
} else
|
||||||
if (strcmp(cmd, "PWD" == 0) {
|
if (strcmp(cmd, "PWD") == 0) {
|
||||||
handle_PWD(cfg, client);
|
handle_PWD(cfg, client);
|
||||||
} else
|
} else
|
||||||
if (strcmp(cmd, "TYPE") == 0) {
|
if (strcmp(cmd, "TYPE") == 0) {
|
||||||
handle_TYPE(cfg, client);
|
handle_TYPE(cfg, client);
|
||||||
} else
|
} else
|
||||||
if (strcmp(cmd, "CWD") == 0) {
|
if (strcmp(cmd, "CWD") == 0) {
|
||||||
if (argument_len > 0) {
|
handle_CWD(cfg, client, argument);
|
||||||
|
} else
|
||||||
|
if (strcmp(cmd, "PORT") == 0) {
|
||||||
|
handle_PORT(cfg, client, argument);
|
||||||
|
} else
|
||||||
|
if (strcmp(cmd, "LIST") == 0) {
|
||||||
|
handle_LIST(cfg, client);
|
||||||
|
} else
|
||||||
|
if (strcmp(cmd, "PASV") == 0) {
|
||||||
|
handle_PASV(cfg, client);
|
||||||
|
} else
|
||||||
|
if (strcmp(cmd, "QUIT") == 0) {
|
||||||
|
send_msg(client, "221 Goodbye!\r\n");
|
||||||
|
} else
|
||||||
|
if (strcmp(cmd, "RETR") == 0) {
|
||||||
|
handle_RETR(cfg, client, argument);
|
||||||
} else {
|
} else {
|
||||||
|
send_msg(client, "500 Command not recognized.\r\n");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -204,10 +556,11 @@ void init(struct ftpserver *cfg) {
|
|||||||
struct sockaddr_in server, client;
|
struct sockaddr_in server, client;
|
||||||
fd_set master, read_fds;
|
fd_set master, read_fds;
|
||||||
int fdmax = 0;
|
int fdmax = 0;
|
||||||
int c;
|
socklen_t c;
|
||||||
int i,j,k;
|
int i,j,k;
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
|
int new_fd;
|
||||||
|
int nbytes;
|
||||||
server_socket = socket(AF_INET, SOCK_STREAM, 0);
|
server_socket = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
if (server_socket == -1) {
|
if (server_socket == -1) {
|
||||||
fprintf(stderr, "Couldn't create socket..\n");
|
fprintf(stderr, "Couldn't create socket..\n");
|
||||||
@ -228,13 +581,16 @@ void init(struct ftpserver *cfg) {
|
|||||||
|
|
||||||
FD_ZERO(&master);
|
FD_ZERO(&master);
|
||||||
FD_SET(server_socket, &master);
|
FD_SET(server_socket, &master);
|
||||||
fd_max = server_socket;
|
fdmax = server_socket;
|
||||||
|
|
||||||
c = sizeof(struct sockaddr_in);
|
c = sizeof(struct sockaddr_in);
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
read_fds = master;
|
read_fds = master;
|
||||||
if (select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1) {
|
if (select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1) {
|
||||||
|
if (errno == EINTR) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
perror("select");
|
perror("select");
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
@ -254,16 +610,21 @@ void init(struct ftpserver *cfg) {
|
|||||||
|
|
||||||
if (!clients) {
|
if (!clients) {
|
||||||
fprintf(stderr, "Out of memory!\n");
|
fprintf(stderr, "Out of memory!\n");
|
||||||
return -1;
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
clients[client_count] = (struct ftpclient *)malloc(sizeof(struct ftpclient));
|
clients[client_count] = (struct ftpclient *)malloc(sizeof(struct ftpclient));
|
||||||
|
|
||||||
|
memset(clients[client_count], 0, sizeof(struct ftpclient));
|
||||||
|
|
||||||
if (!clients[client_count]) {
|
if (!clients[client_count]) {
|
||||||
fprintf(stderr, "Out of memory!\n");
|
fprintf(stderr, "Out of memory!\n");
|
||||||
return -1;
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getpeername(new_fd, (struct sockaddr *)&client, &c);
|
||||||
|
inet_ntop(AF_INET, &(client.sin_addr), clients[client_count]->ip, INET_ADDRSTRLEN);
|
||||||
|
|
||||||
clients[client_count]->fd = new_fd;
|
clients[client_count]->fd = new_fd;
|
||||||
strcpy(clients[client_count]->current_path, "/");
|
strcpy(clients[client_count]->current_path, "/");
|
||||||
clients[client_count]->data_socket = -1;
|
clients[client_count]->data_socket = -1;
|
||||||
@ -287,12 +648,22 @@ void init(struct ftpserver *cfg) {
|
|||||||
if ((nbytes = recv(i, buf, sizeof buf, 0)) <= 0) {
|
if ((nbytes = recv(i, buf, sizeof buf, 0)) <= 0) {
|
||||||
for (k=0;k<client_count;k++) {
|
for (k=0;k<client_count;k++) {
|
||||||
if (clients[k]->fd == i) {
|
if (clients[k]->fd == i) {
|
||||||
|
if (clients[k]->data_socket > 0) {
|
||||||
|
close(clients[k]->data_socket);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clients[k]->data_srv_socket > 0) {
|
||||||
|
close(clients[k]->data_srv_socket);
|
||||||
|
}
|
||||||
|
|
||||||
free(clients[k]);
|
free(clients[k]);
|
||||||
|
|
||||||
for (j=k;j<client_count-1;j++) {
|
for (j=k;j<client_count-1;j++) {
|
||||||
clients[j] = clients[j+1];
|
clients[j] = clients[j+1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
client_count--;
|
client_count--;
|
||||||
|
|
||||||
if (client_count == 0) {
|
if (client_count == 0) {
|
||||||
@ -334,11 +705,21 @@ void init(struct ftpserver *cfg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
|
struct sigaction sa;
|
||||||
struct ftpserver ftpsrv;
|
struct ftpserver ftpsrv;
|
||||||
ftpsrv.port = 2121;
|
ftpsrv.port = 2121;
|
||||||
ftpsrv.userdb = NULL;
|
ftpsrv.userdb = NULL;
|
||||||
ftpsrv.fileroot = NULL;
|
ftpsrv.fileroot = NULL;
|
||||||
|
|
||||||
|
sa.sa_handler = sigchld_handler; // reap all dead processes
|
||||||
|
sigemptyset(&sa.sa_mask);
|
||||||
|
sa.sa_flags = SA_RESTART | SA_SIGINFO;
|
||||||
|
if (sigaction(SIGCHLD, &sa, NULL) == -1) {
|
||||||
|
perror("sigaction - sigchld");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
fprintf(stderr, "Usage: %s [config.ini]\n", argv[0]);
|
fprintf(stderr, "Usage: %s [config.ini]\n", argv[0]);
|
||||||
exit(-1);
|
exit(-1);
|
||||||
|
@ -8,7 +8,7 @@ struct ftpclient {
|
|||||||
char data_ip[20];
|
char data_ip[20];
|
||||||
int data_port;
|
int data_port;
|
||||||
int type;
|
int type;
|
||||||
// char ip[20];
|
char ip[20];
|
||||||
char name[16];
|
char name[16];
|
||||||
char password[32];
|
char password[32];
|
||||||
int data_srv_socket;
|
int data_srv_socket;
|
||||||
|
Reference in New Issue
Block a user