More work on ftp server
This commit is contained in:
parent
d9d0b6f89e
commit
c3c682cad1
@ -14,6 +14,7 @@
|
|||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <time.h>
|
||||||
#include "magiftpd.h"
|
#include "magiftpd.h"
|
||||||
#include "../../inih/ini.h"
|
#include "../../inih/ini.h"
|
||||||
|
|
||||||
@ -36,6 +37,84 @@ void sigchld_handler(int s)
|
|||||||
errno = saved_errno;
|
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) {
|
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;
|
||||||
|
|
||||||
@ -197,10 +276,20 @@ void handle_PASV(struct ftpserver *cfg, struct ftpclient *client) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void handle_RETR(struct ftpserver *cfg, struct ftpclient *client, char *file) {
|
void handle_RETR(struct ftpserver *cfg, struct ftpclient *client, char *file) {
|
||||||
char newpath[PATH_MAX];
|
char *newpath;
|
||||||
|
char fullpath[PATH_MAX];
|
||||||
FILE *fptr;
|
FILE *fptr;
|
||||||
char buffer[1024];
|
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;
|
struct stat s;
|
||||||
pid_t pid = fork();
|
pid_t pid = fork();
|
||||||
int n;
|
int n;
|
||||||
@ -209,9 +298,9 @@ void handle_RETR(struct ftpserver *cfg, struct ftpclient *client, char *file) {
|
|||||||
// nothing
|
// nothing
|
||||||
} else if (pid == 0) {
|
} else if (pid == 0) {
|
||||||
|
|
||||||
if (stat(newpath, &s) == 0) {
|
if (stat(fullpath, &s) == 0) {
|
||||||
if (!S_ISDIR(s.st_mode)) {
|
if (!S_ISDIR(s.st_mode)) {
|
||||||
fptr = fopen(newpath, "rb");
|
fptr = fopen(fullpath, "rb");
|
||||||
if (fptr) {
|
if (fptr) {
|
||||||
if (open_tcp_connection(cfg, client)) {
|
if (open_tcp_connection(cfg, client)) {
|
||||||
send_msg(client, "150 Data connection accepted; transfer starting.\r\n");
|
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);
|
exit(0);
|
||||||
} else {
|
} else {
|
||||||
send_msg(client, "451 RETR Failed.\r\n");
|
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];
|
char newpath[PATH_MAX];
|
||||||
DIR *dirp;
|
DIR *dirp;
|
||||||
struct dirent *dp;
|
struct dirent *dp;
|
||||||
char linebuffer[256];
|
char linebuffer[1024];
|
||||||
snprintf(newpath, PATH_MAX, "%s/%s", cfg->fileroot, client->current_path);
|
snprintf(newpath, PATH_MAX, "%s/%s", cfg->fileroot, client->current_path);
|
||||||
struct stat s;
|
struct stat s;
|
||||||
|
struct tm file_tm;
|
||||||
pid_t pid = fork();
|
pid_t pid = fork();
|
||||||
|
char *days[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
|
||||||
|
|
||||||
if (pid > 0) {
|
if (pid > 0) {
|
||||||
// nothing
|
// nothing
|
||||||
@ -267,7 +358,12 @@ void handle_LIST(struct ftpserver *cfg, struct ftpclient *client) {
|
|||||||
while ((dp = readdir(dirp)) != NULL) {
|
while ((dp = readdir(dirp)) != NULL) {
|
||||||
snprintf(newpath, PATH_MAX, "%s/%s/%s", cfg->fileroot, client->current_path, dp->d_name);
|
snprintf(newpath, PATH_MAX, "%s/%s/%s", cfg->fileroot, client->current_path, dp->d_name);
|
||||||
if (stat(newpath, &s) == 0) {
|
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));
|
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) {
|
void handle_CWD(struct ftpserver *cfg, struct ftpclient *client, char *dir) {
|
||||||
struct dllist *proot;
|
char *newpath;
|
||||||
struct dllist *pptr;
|
char fullpath[PATH_MAX];
|
||||||
char *rescpy;
|
|
||||||
char *ptr;
|
|
||||||
char newpath[PATH_MAX];
|
|
||||||
struct stat s;
|
struct stat s;
|
||||||
|
|
||||||
proot = (struct dllist *)malloc(sizeof(struct dllist));
|
newpath = (char *)malloc(1024);
|
||||||
|
parse_path(client, dir, &newpath);
|
||||||
|
|
||||||
if (!proot) {
|
snprintf(fullpath, PATH_MAX, "%s/%s", cfg->fileroot, newpath);
|
||||||
fprintf(stderr, "Out of memory\n");
|
|
||||||
exit(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
proot->next = NULL;
|
if (stat(fullpath, &s) == 0) {
|
||||||
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)) {
|
if (S_ISDIR(s.st_mode)) {
|
||||||
pptr = proot;
|
strcpy(client->current_path, newpath);
|
||||||
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");
|
send_msg(client, "250 Okay.\r\n");
|
||||||
} else {
|
} else {
|
||||||
send_msg(client, "550 No such file or directory.\r\n");
|
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");
|
send_msg(client, "550 No such file or directory.\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
pptr = proot;
|
free(newpath);
|
||||||
|
|
||||||
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) {
|
||||||
@ -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) {
|
void handle_USER(struct ftpserver *cfg, struct ftpclient *client, char *username) {
|
||||||
fprintf(stderr, "username %s\n", username);
|
|
||||||
strncpy(client->name, username, 16);
|
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) {
|
||||||
@ -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 (strcmp(cmd, "USER") == 0) {
|
||||||
if (argument_len > 0) {
|
if (argument_len > 0) {
|
||||||
handle_USER(cfg, client, argument);
|
handle_USER(cfg, client, argument);
|
||||||
|
Reference in New Issue
Block a user