From 7e51aedc5bdce76c8f6776589bd8a9e2248047c6 Mon Sep 17 00:00:00 2001 From: Tyrolyean Date: Thu, 30 Apr 2020 19:43:44 +0200 Subject: [PATCH] Improved filename handling and securiteee Signed-off-by: Tyrolyean --- include/config.h | 2 +- include/file.h | 5 ++++- src/attach.c | 9 ++++++++- src/config.c | 3 ++- src/file.c | 51 ++++++++++++++++++++++++++++++++++++------------ src/main.c | 10 ++++++++-- 6 files changed, 62 insertions(+), 18 deletions(-) diff --git a/include/config.h b/include/config.h index 9dd62db..1c5ef90 100644 --- a/include/config.h +++ b/include/config.h @@ -24,7 +24,7 @@ extern uint16_t listen_port, forward_port; /* Used as booleans, but integers for getops sake... */ -extern int abort_on_pgp, abort_on_dkim; +extern int abort_on_pgp, abort_on_dkim, only_base64; extern char* instance_id; diff --git a/include/file.h b/include/file.h index 20659b9..c1911a0 100644 --- a/include/file.h +++ b/include/file.h @@ -25,9 +25,12 @@ char* generate_safe_dirname(); int base64_decode_file(const char* directory, const struct email_t* mail); + int decode_file(const char* directory, const char * message, size_t len, - struct type_file_info_t finf); + char* name); bool file_exists(const char* filename); +char* sanitizie_filename(char* filename); + #endif /* FILE_H */ diff --git a/src/attach.c b/src/attach.c index 6d6be2b..ca9c6b0 100644 --- a/src/attach.c +++ b/src/attach.c @@ -212,6 +212,9 @@ void unravel_multipart_mail(struct email_t* mail){ void free_submails(struct email_t* mail){ + free(mail->file_info.name); + free(mail->file_info.mime_type); + if(!mail->is_multipart){ return; } @@ -336,6 +339,10 @@ int replace_base64_files(struct email_t* mail, const char* dirname){ return 0; } + if(mail->file_info.name == NULL){ + return 0; + } + if(mail->base64_encoded){ if(base64_decode_file(dirname, mail) < 0){ fprintf(stderr, "Failed to decode base64 file\n!"); @@ -344,7 +351,7 @@ int replace_base64_files(struct email_t* mail, const char* dirname){ }else{ if(decode_file(dirname, (mail->message+mail->body_offset), (mail->message_length - mail->body_offset), - mail->file_info) < 0){ + mail->file_info.name) < 0){ fprintf(stderr, "Failed to decode base64 file\n!"); return -1; diff --git a/src/config.c b/src/config.c index 5a65cc6..fb2f8d1 100644 --- a/src/config.c +++ b/src/config.c @@ -20,10 +20,11 @@ #include uint16_t listen_port = 4269, forward_port = 4270; -int abort_on_pgp = true, abort_on_dkim = true; +int abort_on_pgp = true, abort_on_dkim = true, only_base64 = true; char* instance_id = NULL; int verbose = false; char* directory = NULL; char* url_base = NULL; + diff --git a/src/file.c b/src/file.c index 99d45b6..934ef54 100644 --- a/src/file.c +++ b/src/file.c @@ -27,6 +27,7 @@ #include #include #include +#include /* Generate a safe directory name to store ONE emails files into. This is * done to prevent someone from guessing the directory names. THe first part @@ -44,14 +45,14 @@ char* generate_safe_dirname(){ #define TIME_LEN 30 char datestr[TIME_LEN]; memset(datestr, 0, TIME_LEN); - strftime(datestr, TIME_LEN, "%FT%T%z", info); + strftime(datestr, TIME_LEN, "%FT%H%M", info); /* Get data from urandom to be secure. I mean from what I * know it should be, but I'm not a crypto expert. If you have doubts * and know how I should do that, PLEASE TELL ME! The man pages told me * to do so! */ - int randie[3]; + int randie[2]; if(getrandom(randie, sizeof(randie), 0) <= 0){ perror("Failed to get random seed! Aborting"); @@ -62,8 +63,8 @@ char* generate_safe_dirname(){ char * dir_id = malloc(dir_len+1); memset(dir_id, 0, dir_len+1 ); - snprintf(dir_id,dir_len, "%s/%s%i%i%i/",directory, datestr, - randie[0], randie[1], randie[2]); + snprintf(dir_id,dir_len, "%s/%s%i%i/",directory, datestr, + randie[0], randie[1]); #undef TIME_LEN return dir_id; } @@ -90,7 +91,8 @@ int base64_decode_file(const char* directory, const struct email_t* mail){ return -1; } - int n = decode_file(directory,(char*) decoded, dec_len, mail->file_info); + int n = decode_file(directory,(char*) decoded, dec_len, + mail->file_info.name); free(decoded); @@ -99,15 +101,16 @@ int base64_decode_file(const char* directory, const struct email_t* mail){ } int decode_file(const char* directory, const char * message, size_t len, - struct type_file_info_t finf){ + char* name){ - if(directory == NULL || message == NULL || finf.name == NULL){ + if(directory == NULL || message == NULL || name == NULL){ /* I don't know how I should call that file! */ return 0; } + char* sane_name = sanitizie_filename(name); - size_t fn_len = strlen(finf.name) + strlen(directory) + 1; + size_t fn_len = strlen(sane_name) + strlen(directory) + 1; char* filename = malloc(fn_len); if(filename == NULL){ @@ -116,20 +119,24 @@ int decode_file(const char* directory, const char * message, size_t len, memset(filename, 0, fn_len); strcat(filename, directory); - strcat(filename, finf.name); - + strcat(filename, sane_name); + + bool exists = false; for(size_t i = 0; i < 10; i++){ exists = file_exists(filename); if(exists){ free(filename); - fn_len = strlen(finf.name) + + fn_len = strlen(sane_name) + strlen(directory) + 20; filename = malloc(fn_len); snprintf(filename, fn_len, "%s%i-%s",directory, - rand(), finf.name); + rand(), sane_name); } } + + free(sane_name); + if(exists){ /* What?*/ fprintf(stderr,"Failed to create unique file name!\n"); @@ -164,3 +171,23 @@ bool file_exists(const char* filename){ return false; } } + +/* Generates a filename which should fit into a URL without URL-encode and which + * doesn't allow for */ +char* sanitizie_filename(char* filename){ + + if(filename == NULL){ + return NULL; + } + size_t filename_len = strlen(filename); + size_t new_len = 0; + char* new_name = malloc(filename_len + 1); + memset(new_name, 0, filename_len+1); + for(size_t i = 0; i < filename_len; i++){ + if(isalnum(filename[i]) || filename[i] == '-' || + filename[i] == '.'){ + new_name[new_len++] = filename[i]; + } + } + return new_name; +} diff --git a/src/main.c b/src/main.c index 11d1e08..213dfb5 100644 --- a/src/main.c +++ b/src/main.c @@ -30,6 +30,8 @@ int main(int argc, char* argv[]){ {"noabort-dkim",no_argument, &abort_on_dkim,0}, {"verbose", no_argument, &verbose, 1}, {"quiet", no_argument, &verbose, 0}, + {"only-base64", no_argument, &only_base64, 1}, + {"other-base64",no_argument, &only_base64, 0}, {"in-port", required_argument, 0, 'i'}, {"out-port", required_argument, 0, 'o'}, {"instance-id", required_argument, 0, 'n'}, @@ -106,15 +108,19 @@ int main(int argc, char* argv[]){ printf("Incoming port: %u outgoing port: %u on loopback " "interface\n", listen_port, forward_port); - printf("Ignoring PGP signed/encrypted messages: %s\n", + printf("Aborting on PGP signed/encrypted messages: %s\n", abort_on_pgp ? "true":false); - printf("Ignoring DKIM signed messages: %s\n", + printf("Aborting on DKIM signed messages: %s\n", abort_on_dkim ? "true" : "false"); printf("Instance id for messages: %s\n", instance_id); + printf("Only saving bas64 encoded files: %s\n", + only_base64 ? "true":false); + + printf("Placing files into [%s] linked by [%s]\n", directory, url_base); }