diff --git a/Makefile b/Makefile index 0406ca9..885b48d 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ SRCDIR := $(CWD)/src INCLUDEDIR := $(CWD)/include # flas -CFLAGS := -O2 -I$(INCLUDEDIR) -Wall -Wextra +CFLAGS := -O2 -I$(INCLUDEDIR) -Wall -Wextra -Wpedantic LDFLAGS := -pthread # target files diff --git a/README b/README index 5573f35..6aa5652 100644 --- a/README +++ b/README @@ -27,7 +27,8 @@ You can specify the following command line options: The outgoing smtp port/the port to which mail ist passed through. --directory -d - The directory inside of which the attachments will be stored in. + The directory inside of which the attachments will be stored in. Please + DON'T specify a / at the end! --url -u The base which should point to the same location as the directory does, diff --git a/include/attach.h b/include/attach.h index 7808f04..c94444c 100644 --- a/include/attach.h +++ b/include/attach.h @@ -32,4 +32,6 @@ void free_submails(struct email_t* mail); char* attach_files(char* message, size_t len); +int replace_base64_files(struct email_t* mail, const char* dirname); + #endif /* ATTACH_H */ diff --git a/include/base64.h b/include/base64.h index 3babc0c..2576e44 100644 --- a/include/base64.h +++ b/include/base64.h @@ -1,97 +1,18 @@ /* - * Copyright (c) 2003 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* ==================================================================== - * Copyright (c) 1995-1999 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. For written permission, please contact - * apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache" - * nor may "Apache" appear in their names without prior written - * permission of the Apache Group. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see . + * Base64 encoding/decoding (RFC1341) + * Copyright (c) 2005, Jouni Malinen * + * This software may be distributed under the terms of the BSD license. */ -/* Base64 encoder/decoder. Originally Apache file ap_base64.c - */ #ifndef BASE64_H #define BASE64_H -extern const unsigned char pr2six[256]; +#include -int Base64decode_len(const char *bufcoded); -int Base64decode(char *bufplain, const char *bufcoded); - -extern const char basis_64[]; - -int Base64encode_len(int len); -int Base64encode(char *encoded, const char *string, int len); +unsigned char * base64_encode(const unsigned char *src, size_t len, + size_t *out_len); +unsigned char * base64_decode(const unsigned char *src, size_t len, + size_t *out_len); #endif /* BASE64_H */ diff --git a/include/file.h b/include/file.h index 4bbab0c..9a57f3e 100644 --- a/include/file.h +++ b/include/file.h @@ -18,27 +18,6 @@ #ifndef FILE_H #define FILE_H - - -char* generate_safe_dirname(){ - - /* Get time */ - time_t rawtime; - struct tm *info; - time( &rawtime ); - info = localtime( &rawtime ); - -#define TIME_LEN 30 - char datestr[TIME_LEN]; - if(datestr == NULL){ - return NULL; - } - strftime(datestr, TIME_LEN, "%FT%T%z", info); - - -#undef TIME_LEN - - -} +char* generate_safe_dirname(); #endif /* FILE_H */ diff --git a/src/attach.c b/src/attach.c index 5afb777..014808c 100644 --- a/src/attach.c +++ b/src/attach.c @@ -21,6 +21,7 @@ #include "config.h" #include "mail.h" #include "tools.h" +#include "file.h" #include #include @@ -283,7 +284,21 @@ char* attach_files(char* message, size_t len){ } /* Now we can start the real work! */ + const char* storage_dir = generate_safe_dirname(); + if(storage_dir == NULL){ + fprintf(stderr,"Failed to get mail storage directory!\n"); + goto finish; + } + if(verbose){ + printf("Storing mail messages into directory [%s]\n", + storage_dir); + } + if(replace_base64_files(email, storage_dir) < 0){ + fprintf(stderr, "Failed to store base64 messages!\n"); + goto finish; + } + /* Announce our presence via header */ if(append_header(email,"X-Mailattached", instance_id) < 0){ fprintf(stderr, "Failed to attach header!\n"); @@ -297,3 +312,24 @@ finish: return mess; } +/* This function RECURSIVELY replaces ALL base 64 encoded messages above the + * threshold set in the config file with links to that file in the HTML format. + * Call this function with the mail ROOT object if you want to replace all + * base64 files, or only one when you want to replace only one. + */ +int replace_base64_files(struct email_t* mail, const char* dirname){ + + if(mail->is_multipart){ + + for(size_t i = 0; i < mail->submes_cnt; i++){ + if(replace_base64_files(mail->submes[i], dirname) < 0){ + return -1; + } + } + return 0; + + } + + + return 0; +} diff --git a/src/base64.c b/src/base64.c index bc164ab..98732c4 100644 --- a/src/base64.c +++ b/src/base64.c @@ -1,209 +1,155 @@ /* - * Copyright (c) 2003 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* ==================================================================== - * Copyright (c) 1995-1999 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. For written permission, please contact - * apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache" - * nor may "Apache" appear in their names without prior written - * permission of the Apache Group. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see . + * Base64 encoding/decoding (RFC1341) + * Copyright (c) 2005-2011, Jouni Malinen * + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ -/* Base64 encoder/decoder. Originally Apache file ap_base64.c - */ - +#include #include - +#include #include "base64.h" -/* aaaack but it's fast and const should make it shared text page. */ -const unsigned char pr2six[256] = +static const unsigned char base64_table[65] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +/** + * base64_encode - Base64 encode + * @src: Data to be encoded + * @len: Length of the data to be encoded + * @out_len: Pointer to output length variable, or %NULL if not used + * Returns: Allocated buffer of out_len bytes of encoded data, + * or %NULL on failure + * + * Caller is responsible for freeing the returned buffer. Returned buffer is + * nul terminated to make it easier to use as a C string. The nul terminator is + * not included in out_len. + */ +unsigned char * base64_encode(const unsigned char *src, size_t len, + size_t *out_len) { - /* ASCII table */ - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64, - 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64, - 64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64 -}; + unsigned char *out, *pos; + const unsigned char *end, *in; + size_t olen; + int line_len; -int Base64decode_len(const char *bufcoded) -{ - int nbytesdecoded; - register const unsigned char *bufin; - register int nprbytes; + olen = len * 4 / 3 + 4; /* 3-byte blocks to 4-byte */ + olen += olen / 72; /* line feeds */ + olen++; /* nul termination */ + if (olen < len) + return NULL; /* integer overflow */ + out = malloc(olen); + if (out == NULL) + return NULL; - bufin = (const unsigned char *) bufcoded; - while (pr2six[*(bufin++)] <= 63); + end = src + len; + in = src; + pos = out; + line_len = 0; + while (end - in >= 3) { + *pos++ = base64_table[in[0] >> 2]; + *pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)]; + *pos++ = base64_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)]; + *pos++ = base64_table[in[2] & 0x3f]; + in += 3; + line_len += 4; + if (line_len >= 72) { + *pos++ = '\n'; + line_len = 0; + } + } - nprbytes = (bufin - (const unsigned char *) bufcoded) - 1; - nbytesdecoded = ((nprbytes + 3) / 4) * 3; + if (end - in) { + *pos++ = base64_table[in[0] >> 2]; + if (end - in == 1) { + *pos++ = base64_table[(in[0] & 0x03) << 4]; + *pos++ = '='; + } else { + *pos++ = base64_table[((in[0] & 0x03) << 4) | + (in[1] >> 4)]; + *pos++ = base64_table[(in[1] & 0x0f) << 2]; + } + *pos++ = '='; + line_len += 4; + } - return nbytesdecoded + 1; + if (line_len) + *pos++ = '\n'; + + *pos = '\0'; + if (out_len) + *out_len = pos - out; + return out; } -int Base64decode(char *bufplain, const char *bufcoded) + +/** + * base64_decode - Base64 decode + * @src: Data to be decoded + * @len: Length of the data to be decoded + * @out_len: Pointer to output length variable + * Returns: Allocated buffer of out_len bytes of decoded data, + * or %NULL on failure + * + * Caller is responsible for freeing the returned buffer. + */ +unsigned char * base64_decode(const unsigned char *src, size_t len, + size_t *out_len) { - int nbytesdecoded; - register const unsigned char *bufin; - register unsigned char *bufout; - register int nprbytes; + unsigned char dtable[256], *out, *pos, block[4], tmp; + size_t i, count, olen; + int pad = 0; - bufin = (const unsigned char *) bufcoded; - while (pr2six[*(bufin++)] <= 63); - nprbytes = (bufin - (const unsigned char *) bufcoded) - 1; - nbytesdecoded = ((nprbytes + 3) / 4) * 3; + memset(dtable, 0x80, 256); + for (i = 0; i < sizeof(base64_table) - 1; i++) + dtable[base64_table[i]] = (unsigned char) i; + dtable['='] = 0; - bufout = (unsigned char *) bufplain; - bufin = (const unsigned char *) bufcoded; + count = 0; + for (i = 0; i < len; i++) { + if (dtable[src[i]] != 0x80) + count++; + } - while (nprbytes > 4) { - *(bufout++) = - (unsigned char) (pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4); - *(bufout++) = - (unsigned char) (pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2); - *(bufout++) = - (unsigned char) (pr2six[bufin[2]] << 6 | pr2six[bufin[3]]); - bufin += 4; - nprbytes -= 4; - } + if (count == 0 || count % 4) + return NULL; - /* Note: (nprbytes == 1) would be an error, so just ingore that case */ - if (nprbytes > 1) { - *(bufout++) = - (unsigned char) (pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4); - } - if (nprbytes > 2) { - *(bufout++) = - (unsigned char) (pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2); - } - if (nprbytes > 3) { - *(bufout++) = - (unsigned char) (pr2six[bufin[2]] << 6 | pr2six[bufin[3]]); - } + olen = count / 4 * 3; + pos = out = malloc(olen); + if (out == NULL) + return NULL; - *(bufout++) = '\0'; - nbytesdecoded -= (4 - nprbytes) & 3; - return nbytesdecoded; -} - -const char basis_64[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - -int Base64encode_len(int len) -{ - return ((len + 2) / 3 * 4) + 1; -} - -int Base64encode(char *encoded, const char *string, int len) -{ - int i; - char *p; - - p = encoded; - for (i = 0; i < len - 2; i += 3) { - *p++ = basis_64[(string[i] >> 2) & 0x3F]; - *p++ = basis_64[((string[i] & 0x3) << 4) | - ((int) (string[i + 1] & 0xF0) >> 4)]; - *p++ = basis_64[((string[i + 1] & 0xF) << 2) | - ((int) (string[i + 2] & 0xC0) >> 6)]; - *p++ = basis_64[string[i + 2] & 0x3F]; - } - if (i < len) { - *p++ = basis_64[(string[i] >> 2) & 0x3F]; - if (i == (len - 1)) { - *p++ = basis_64[((string[i] & 0x3) << 4)]; - *p++ = '='; - } - else { - *p++ = basis_64[((string[i] & 0x3) << 4) | - ((int) (string[i + 1] & 0xF0) >> 4)]; - *p++ = basis_64[((string[i + 1] & 0xF) << 2)]; - } - *p++ = '='; - } - - *p++ = '\0'; - return p - encoded; + count = 0; + for (i = 0; i < len; i++) { + tmp = dtable[src[i]]; + if (tmp == 0x80) + continue; + + if (src[i] == '=') + pad++; + block[count] = tmp; + count++; + if (count == 4) { + *pos++ = (block[0] << 2) | (block[1] >> 4); + *pos++ = (block[1] << 4) | (block[2] >> 2); + *pos++ = (block[2] << 6) | block[3]; + count = 0; + if (pad) { + if (pad == 1) + pos--; + else if (pad == 2) + pos -= 2; + else { + /* Invalid padding */ + free(out); + return NULL; + } + break; + } + } + } + + *out_len = pos - out; + return out; } diff --git a/src/file.c b/src/file.c index 4bbab0c..fcd3f34 100644 --- a/src/file.c +++ b/src/file.c @@ -1,5 +1,5 @@ /* - * file.h - File writing functionality + * file.c - File writing functionality * The author licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance @@ -15,11 +15,22 @@ * under the License. */ -#ifndef FILE_H -#define FILE_H - +#include "file.h" +#include "config.h" +#include +#include +#include +#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 + * is the date in ISO format, in case you want to have a shell script cleaning + * the directory every once in a while. + */ char* generate_safe_dirname(){ /* Get time */ @@ -30,15 +41,40 @@ char* generate_safe_dirname(){ #define TIME_LEN 30 char datestr[TIME_LEN]; - if(datestr == NULL){ - return NULL; - } + memset(datestr, 0, TIME_LEN); strftime(datestr, TIME_LEN, "%FT%T%z", 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 random_fd = open("/dev/random", O_RDONLY); + if (random_fd < 0){ + perror("Failed to open /dev/urandom"); + return NULL; + }else{ + size_t randie_len = 0; + while (randie_len < sizeof(randie)){ + ssize_t result = read(random_fd, randie + randie_len, sizeof(randie) - randie_len); + if (result < 0){ + + perror("Failed to read from /dev/urandom"); + close(random_fd); + return NULL; + } + randie_len += result; + } + close(random_fd); + } + size_t dir_len = TIME_LEN + 50 + strlen(directory); + 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]); #undef TIME_LEN - - + return dir_id; } -#endif /* FILE_H */