More work on ftp server

This commit is contained in:
Andrew Pamment 2017-03-21 21:23:12 +10:00
parent d9d0b6f89e
commit c3c682cad1

View File

@ -14,6 +14,7 @@
#include <dirent.h>
#include <signal.h>
#include <errno.h>
#include <time.h>
#include "magiftpd.h"
#include "../../inih/ini.h"
@ -36,6 +37,84 @@ void sigchld_handler(int s)
errno = saved_errno;
}
static void parse_path(struct ftpclient *client, char *path, char **result) {
struct dllist *proot;
struct dllist *pptr;
char *rescpy;
char *ptr;
char *newpath = *result;
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 (path[0] == '/') {
rescpy = strdup(path);
} else {
rescpy = (char *)malloc(strlen(path) + strlen(client->current_path) + 2);
if (!rescpy) {
fprintf(stderr, "Out of memory\n");
exit(-1);
}
sprintf(rescpy, "%s/%s", client->current_path, path);
}
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;
pptr = pptr->next;
}
ptr = strtok(NULL, "/");
}
newpath[0] = '\0';
pptr = proot;
while (pptr != NULL && pptr->data != NULL) {
snprintf(newpath, PATH_MAX, "%s/%s", newpath, pptr->data);
pptr = pptr->next;
}
pptr = proot;
while (pptr != NULL) {
if (pptr->next != NULL) {
pptr = pptr->next;
free(pptr->prev);
} else {
free(pptr);
pptr = NULL;
}
}
free(rescpy);
}
static int handler(void* user, const char* section, const char* name, const char* value) {
struct ftpserver *cfg = (struct ftpserver *)user;
@ -197,10 +276,20 @@ void handle_PASV(struct ftpserver *cfg, struct ftpclient *client) {
}
void handle_RETR(struct ftpserver *cfg, struct ftpclient *client, char *file) {
char newpath[PATH_MAX];
char *newpath;
char fullpath[PATH_MAX];
FILE *fptr;
char buffer[1024];
snprintf(newpath, PATH_MAX, "%s/%s/%s", cfg->fileroot, client->current_path, file);
newpath = (char *)malloc(1024);
parse_path(client, file, &newpath);
if (newpath[0] == '/') {
snprintf(fullpath, PATH_MAX, "%s%s", cfg->fileroot, newpath);
} else {
snprintf(fullpath, PATH_MAX, "%s/%s/%s", cfg->fileroot, client->current_path, newpath);
}
free(newpath);
struct stat s;
pid_t pid = fork();
int n;
@ -209,9 +298,9 @@ void handle_RETR(struct ftpserver *cfg, struct ftpclient *client, char *file) {
// nothing
} else if (pid == 0) {
if (stat(newpath, &s) == 0) {
if (stat(fullpath, &s) == 0) {
if (!S_ISDIR(s.st_mode)) {
fptr = fopen(newpath, "rb");
fptr = fopen(fullpath, "rb");
if (fptr) {
if (open_tcp_connection(cfg, client)) {
send_msg(client, "150 Data connection accepted; transfer starting.\r\n");
@ -232,7 +321,7 @@ void handle_RETR(struct ftpserver *cfg, struct ftpclient *client, char *file) {
}
}
send_msg(client, "451 RETR Failed\r\n");
send_msg(client, "451 RETR Failed.\r\n");
exit(0);
} else {
send_msg(client, "451 RETR Failed.\r\n");
@ -243,10 +332,12 @@ void handle_LIST(struct ftpserver *cfg, struct ftpclient *client) {
char newpath[PATH_MAX];
DIR *dirp;
struct dirent *dp;
char linebuffer[256];
char linebuffer[1024];
snprintf(newpath, PATH_MAX, "%s/%s", cfg->fileroot, client->current_path);
struct stat s;
struct tm file_tm;
pid_t pid = fork();
char *days[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
if (pid > 0) {
// nothing
@ -267,7 +358,12 @@ void handle_LIST(struct ftpserver *cfg, struct ftpclient *client) {
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) ? '/' : ' '));
localtime_r(&s.st_mtime, &file_tm);
snprintf(linebuffer, 1024, "%c%c%c%c%c%c%c%c%c%c %d %d %d %lld %d %s %02d:%02d %s\r\n", S_ISDIR(s.st_mode) ? 'd' : '-',
S_IRUSR & s.st_mode ? 'r' : '-', S_IWUSR & s.st_mode ? 'w' : '-',S_IXUSR & s.st_mode ? 'x' : '-',
S_IRGRP & s.st_mode ? 'r' : '-', S_IWGRP & s.st_mode ? 'w' : '-',S_IXGRP & s.st_mode ? 'x' : '-',
S_IROTH & s.st_mode ? 'r' : '-', S_IWOTH & s.st_mode ? 'w' : '-',S_IXOTH & s.st_mode ? 'x' : '-',
s.st_nlink, s.st_uid, s.st_gid, s.st_size, file_tm.tm_mday, days[file_tm.tm_wday], file_tm.tm_hour, file_tm.tm_min, dp->d_name);
send_data(client, linebuffer, strlen(linebuffer));
}
}
@ -293,78 +389,18 @@ void handle_PORT(struct ftpserver *cfg, struct ftpclient *client, char *arg) {
}
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];
char *newpath;
char fullpath[PATH_MAX];
struct stat s;
proot = (struct dllist *)malloc(sizeof(struct dllist));
newpath = (char *)malloc(1024);
parse_path(client, dir, &newpath);
if (!proot) {
fprintf(stderr, "Out of memory\n");
exit(-1);
}
snprintf(fullpath, PATH_MAX, "%s/%s", cfg->fileroot, newpath);
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 (stat(fullpath, &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;
}
strcpy(client->current_path, newpath);
send_msg(client, "250 Okay.\r\n");
} else {
send_msg(client, "550 No such file or directory.\r\n");
@ -373,18 +409,7 @@ void handle_CWD(struct ftpserver *cfg, struct ftpclient *client, char *dir) {
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);
free(newpath);
}
void handle_TYPE(struct ftpserver *cfg, struct ftpclient *client) {
@ -463,7 +488,6 @@ void handle_PASS(struct ftpserver *cfg, struct ftpclient *client, char *password
}
void handle_USER(struct ftpserver *cfg, struct ftpclient *client, char *username) {
fprintf(stderr, "username %s\n", username);
strncpy(client->name, username, 16);
client->name[15] = '\0';
if (strcmp(client->name, "anonymous") == 0) {
@ -502,8 +526,6 @@ 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 (argument_len > 0) {
handle_USER(cfg, client, argument);