2012-01-07 16:40:06 +01:00
|
|
|
/*
|
|
|
|
* archive.c, SJ
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
2013-01-11 11:37:23 +01:00
|
|
|
#include <sys/mman.h>
|
2012-01-07 16:40:06 +01:00
|
|
|
#include <fcntl.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <time.h>
|
|
|
|
#include <locale.h>
|
|
|
|
#include <syslog.h>
|
|
|
|
#include <openssl/blowfish.h>
|
|
|
|
#include <openssl/evp.h>
|
|
|
|
#include <zlib.h>
|
|
|
|
#include <assert.h>
|
|
|
|
#include <piler.h>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void zerr(int ret){
|
|
|
|
|
|
|
|
fputs("zpipe: ", stderr);
|
|
|
|
|
|
|
|
switch (ret) {
|
|
|
|
case Z_ERRNO:
|
|
|
|
fputs("I/O error\n", stderr);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Z_STREAM_ERROR:
|
|
|
|
fputs("invalid compression level\n", stderr);
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case Z_DATA_ERROR:
|
|
|
|
fputs("invalid or incomplete deflate data\n", stderr);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Z_MEM_ERROR:
|
|
|
|
fputs("out of memory\n", stderr);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Z_VERSION_ERROR:
|
|
|
|
fputs("zlib version mismatch!\n", stderr);
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int inf(unsigned char *in, int len, int mode, char **buffer, FILE *dest){
|
|
|
|
int ret, pos=0;
|
|
|
|
unsigned have;
|
|
|
|
z_stream strm;
|
|
|
|
char *new_ptr;
|
|
|
|
unsigned char out[REALLYBIGBUFSIZE];
|
|
|
|
|
|
|
|
/* allocate inflate state */
|
|
|
|
|
|
|
|
strm.zalloc = Z_NULL;
|
|
|
|
strm.zfree = Z_NULL;
|
|
|
|
strm.opaque = Z_NULL;
|
|
|
|
strm.avail_in = 0;
|
|
|
|
strm.next_in = Z_NULL;
|
|
|
|
ret = inflateInit(&strm);
|
|
|
|
|
|
|
|
|
|
|
|
if(ret != Z_OK) return ret;
|
|
|
|
|
|
|
|
strm.avail_in = len;
|
|
|
|
strm.next_in = in;
|
|
|
|
|
|
|
|
if(mode == WRITE_TO_BUFFER){
|
|
|
|
*buffer = malloc(REALLYBIGBUFSIZE);
|
|
|
|
if(!*buffer) return Z_MEM_ERROR;
|
|
|
|
memset(*buffer, 0, REALLYBIGBUFSIZE);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
do {
|
|
|
|
strm.avail_out = REALLYBIGBUFSIZE;
|
|
|
|
strm.next_out = out;
|
|
|
|
ret = inflate(&strm, Z_NO_FLUSH);
|
|
|
|
|
|
|
|
assert(ret != Z_STREAM_ERROR); /* state not clobbered */
|
|
|
|
switch (ret) {
|
|
|
|
case Z_NEED_DICT:
|
|
|
|
ret = Z_DATA_ERROR; /* and fall through */
|
|
|
|
case Z_DATA_ERROR:
|
|
|
|
case Z_MEM_ERROR:
|
|
|
|
(void)inflateEnd(&strm);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
have = REALLYBIGBUFSIZE - strm.avail_out;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* write the uncompressed result either to stdout
|
|
|
|
* or to the buffer
|
|
|
|
*/
|
|
|
|
|
|
|
|
if(mode == WRITE_TO_STDOUT){
|
|
|
|
if(fwrite(out, 1, have, dest) != have){
|
|
|
|
(void)inflateEnd(&strm);
|
|
|
|
return Z_ERRNO;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
memcpy(*buffer+pos, out, have);
|
|
|
|
pos += have;
|
|
|
|
new_ptr = realloc(*buffer, pos+REALLYBIGBUFSIZE);
|
|
|
|
if(!new_ptr){
|
|
|
|
(void)inflateEnd(&strm);
|
|
|
|
return Z_MEM_ERROR;
|
|
|
|
}
|
|
|
|
*buffer = new_ptr;
|
|
|
|
memset(*buffer+pos, 0, REALLYBIGBUFSIZE);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
} while (strm.avail_out == 0);
|
|
|
|
|
|
|
|
|
|
|
|
(void)inflateEnd(&strm);
|
|
|
|
|
|
|
|
return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int retrieve_file_from_archive(char *filename, int mode, char **buffer, FILE *dest, struct __config *cfg){
|
|
|
|
int rc=0, n, olen, tlen, len, fd=-1;
|
2013-01-11 11:37:23 +01:00
|
|
|
unsigned char *s=NULL, *addr=NULL, inbuf[REALLYBIGBUFSIZE];
|
2012-01-07 16:40:06 +01:00
|
|
|
struct stat st;
|
|
|
|
EVP_CIPHER_CTX ctx;
|
|
|
|
|
|
|
|
|
|
|
|
if(filename == NULL) return 1;
|
|
|
|
|
|
|
|
|
|
|
|
fd = open(filename, O_RDONLY);
|
|
|
|
if(fd == -1){
|
2012-10-23 10:12:56 +02:00
|
|
|
syslog(LOG_PRIORITY, "%s: cannot open()", filename);
|
2012-01-07 16:40:06 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if(fstat(fd, &st)){
|
2012-10-23 10:12:56 +02:00
|
|
|
syslog(LOG_PRIORITY, "%s: cannot fstat()", filename);
|
2012-01-07 16:40:06 +01:00
|
|
|
close(fd);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-01-11 11:37:23 +01:00
|
|
|
if(cfg->encrypt_messages == 1){
|
|
|
|
EVP_CIPHER_CTX_init(&ctx);
|
|
|
|
EVP_DecryptInit_ex(&ctx, EVP_bf_cbc(), NULL, cfg->key, cfg->iv);
|
2012-01-07 16:40:06 +01:00
|
|
|
|
2013-01-11 11:37:23 +01:00
|
|
|
len = st.st_size+EVP_MAX_BLOCK_LENGTH;
|
2012-01-07 16:40:06 +01:00
|
|
|
|
2013-01-11 11:37:23 +01:00
|
|
|
s = malloc(len);
|
2012-01-07 16:40:06 +01:00
|
|
|
|
2013-01-11 11:37:23 +01:00
|
|
|
if(!s){
|
|
|
|
printf("malloc()\n");
|
|
|
|
goto CLEANUP;
|
|
|
|
}
|
2012-01-07 16:40:06 +01:00
|
|
|
|
2013-01-11 11:37:23 +01:00
|
|
|
tlen = 0;
|
|
|
|
|
|
|
|
while((n = read(fd, inbuf, sizeof(inbuf)))){
|
|
|
|
|
|
|
|
if(!EVP_DecryptUpdate(&ctx, s+tlen, &olen, inbuf, n)){
|
|
|
|
syslog(LOG_PRIORITY, "%s: EVP_DecryptUpdate()", filename);
|
|
|
|
goto CLEANUP;
|
|
|
|
}
|
2012-01-07 16:40:06 +01:00
|
|
|
|
2013-01-11 11:37:23 +01:00
|
|
|
tlen += olen;
|
|
|
|
}
|
2012-01-07 16:40:06 +01:00
|
|
|
|
|
|
|
|
2013-01-11 11:37:23 +01:00
|
|
|
if(EVP_DecryptFinal(&ctx, s + tlen, &olen) != 1){
|
|
|
|
syslog(LOG_PRIORITY, "%s: EVP_DecryptFinal()", filename);
|
2012-01-07 16:40:06 +01:00
|
|
|
goto CLEANUP;
|
|
|
|
}
|
|
|
|
|
2013-01-11 11:37:23 +01:00
|
|
|
|
2012-01-07 16:40:06 +01:00
|
|
|
tlen += olen;
|
2013-01-11 11:37:23 +01:00
|
|
|
rc = inf(s, tlen, mode, buffer, dest);
|
2012-01-07 16:40:06 +01:00
|
|
|
}
|
2013-01-11 11:37:23 +01:00
|
|
|
else {
|
|
|
|
addr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
|
|
|
rc = inf(addr, st.st_size, mode, buffer, dest);
|
|
|
|
munmap(addr, st.st_size);
|
2012-01-07 16:40:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if(rc != Z_OK) zerr(rc);
|
|
|
|
|
|
|
|
|
|
|
|
CLEANUP:
|
|
|
|
if(fd != -1) close(fd);
|
|
|
|
if(s) free(s);
|
2013-01-11 11:37:23 +01:00
|
|
|
if(cfg->encrypt_messages == 1) EVP_CIPHER_CTX_cleanup(&ctx);
|
2012-01-07 16:40:06 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-04-18 16:49:18 +02:00
|
|
|
int file_from_archive_to_network(char *filename, int sd, int tls_enable, struct __data *data, struct __config *cfg){
|
2013-04-09 14:50:27 +02:00
|
|
|
int n, olen, tlen, len, fd=-1;
|
|
|
|
unsigned char *s=NULL, *addr=NULL, inbuf[REALLYBIGBUFSIZE];
|
|
|
|
struct stat st;
|
|
|
|
EVP_CIPHER_CTX ctx;
|
|
|
|
|
|
|
|
|
|
|
|
if(filename == NULL) return 1;
|
|
|
|
|
|
|
|
|
|
|
|
fd = open(filename, O_RDONLY);
|
|
|
|
if(fd == -1){
|
|
|
|
syslog(LOG_PRIORITY, "%s: cannot open()", filename);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if(fstat(fd, &st)){
|
|
|
|
syslog(LOG_PRIORITY, "%s: cannot fstat()", filename);
|
|
|
|
close(fd);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if(cfg->encrypt_messages == 1){
|
|
|
|
EVP_CIPHER_CTX_init(&ctx);
|
|
|
|
EVP_DecryptInit_ex(&ctx, EVP_bf_cbc(), NULL, cfg->key, cfg->iv);
|
|
|
|
|
|
|
|
len = st.st_size+EVP_MAX_BLOCK_LENGTH;
|
|
|
|
|
|
|
|
s = malloc(len);
|
|
|
|
|
|
|
|
if(!s){
|
|
|
|
syslog(LOG_PRIORITY, "error: malloc(), '%s'", filename);
|
|
|
|
goto CLEANUP2;
|
|
|
|
}
|
|
|
|
|
|
|
|
tlen = 0;
|
|
|
|
|
|
|
|
while((n = read(fd, inbuf, sizeof(inbuf)))){
|
|
|
|
|
|
|
|
if(!EVP_DecryptUpdate(&ctx, s+tlen, &olen, inbuf, n)){
|
|
|
|
syslog(LOG_PRIORITY, "%s: EVP_DecryptUpdate()", filename);
|
|
|
|
goto CLEANUP2;
|
|
|
|
}
|
|
|
|
|
|
|
|
tlen += olen;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if(EVP_DecryptFinal(&ctx, s + tlen, &olen) != 1){
|
|
|
|
syslog(LOG_PRIORITY, "%s: EVP_DecryptFinal()", filename);
|
|
|
|
goto CLEANUP2;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
tlen += olen;
|
2013-04-18 16:49:18 +02:00
|
|
|
write1(sd, s, tlen, tls_enable, data->ssl);
|
2013-04-09 14:50:27 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
addr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
2013-04-18 16:49:18 +02:00
|
|
|
write1(sd, addr, st.st_size, tls_enable, data->ssl);
|
2013-04-09 14:50:27 +02:00
|
|
|
munmap(addr, st.st_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CLEANUP2:
|
|
|
|
if(fd != -1) close(fd);
|
|
|
|
if(s) free(s);
|
|
|
|
if(cfg->encrypt_messages == 1) EVP_CIPHER_CTX_cleanup(&ctx);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-01-28 12:10:39 +01:00
|
|
|
int retrieve_email_from_archive(struct session_data *sdata, struct __data *data, FILE *dest, struct __config *cfg){
|
2012-11-03 23:42:36 +01:00
|
|
|
int i, attachments;
|
2012-01-07 16:40:06 +01:00
|
|
|
char *buffer=NULL, *saved_buffer, *p, filename[SMALLBUFSIZE], pointer[SMALLBUFSIZE];
|
|
|
|
struct ptr_array ptr_arr[MAX_ATTACHMENTS];
|
2012-12-15 09:57:24 +01:00
|
|
|
struct stat st;
|
|
|
|
|
2012-01-07 16:40:06 +01:00
|
|
|
|
|
|
|
if(strlen(sdata->ttmpfile) != RND_STR_LEN){
|
|
|
|
printf("invalid piler-id: %s\n", sdata->ttmpfile);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2013-01-28 12:10:39 +01:00
|
|
|
attachments = query_attachments(sdata, data, &ptr_arr[0], cfg);
|
2012-01-07 16:40:06 +01:00
|
|
|
|
|
|
|
if(attachments == -1){
|
|
|
|
printf("problem querying the attachment of %s\n", sdata->ttmpfile);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2013-02-15 20:58:58 +01:00
|
|
|
snprintf(filename, sizeof(filename)-1, "%s/%02x/%c%c%c/%c%c/%c%c/%s.m", cfg->queuedir, cfg->server_id, *(sdata->ttmpfile+8), *(sdata->ttmpfile+9), *(sdata->ttmpfile+10), *(sdata->ttmpfile+RND_STR_LEN-4), *(sdata->ttmpfile+RND_STR_LEN-3), *(sdata->ttmpfile+RND_STR_LEN-2), *(sdata->ttmpfile+RND_STR_LEN-1), sdata->ttmpfile);
|
2012-12-15 09:57:24 +01:00
|
|
|
if(stat(filename, &st)){
|
2013-02-15 20:58:58 +01:00
|
|
|
snprintf(filename, sizeof(filename)-1, "%s/%02x/%c%c/%c%c/%c%c/%s.m", cfg->queuedir, cfg->server_id, *(sdata->ttmpfile+RND_STR_LEN-6), *(sdata->ttmpfile+RND_STR_LEN-5), *(sdata->ttmpfile+RND_STR_LEN-4), *(sdata->ttmpfile+RND_STR_LEN-3), *(sdata->ttmpfile+RND_STR_LEN-2), *(sdata->ttmpfile+RND_STR_LEN-1), sdata->ttmpfile);
|
2012-12-15 09:57:24 +01:00
|
|
|
}
|
2012-01-07 16:40:06 +01:00
|
|
|
|
|
|
|
if(attachments == 0){
|
2012-11-03 23:42:36 +01:00
|
|
|
retrieve_file_from_archive(filename, WRITE_TO_STDOUT, &buffer, dest, cfg);
|
2012-01-07 16:40:06 +01:00
|
|
|
}
|
|
|
|
else {
|
2012-11-03 23:42:36 +01:00
|
|
|
retrieve_file_from_archive(filename, WRITE_TO_BUFFER, &buffer, dest, cfg);
|
2012-01-07 16:40:06 +01:00
|
|
|
|
|
|
|
if(buffer){
|
|
|
|
saved_buffer = buffer;
|
|
|
|
|
|
|
|
for(i=1; i<=attachments; i++){
|
|
|
|
snprintf(pointer, sizeof(pointer)-1, "ATTACHMENT_POINTER_%s.a%d_XXX_PILER", sdata->ttmpfile, i);
|
|
|
|
|
|
|
|
p = strstr(buffer, pointer);
|
|
|
|
if(p){
|
|
|
|
*p = '\0';
|
2012-11-03 23:42:36 +01:00
|
|
|
fwrite(buffer, 1, p - buffer, dest);
|
2012-01-07 16:40:06 +01:00
|
|
|
buffer = p + strlen(pointer);
|
|
|
|
|
|
|
|
if(strlen(ptr_arr[i].piler_id) == RND_STR_LEN){
|
2013-02-15 20:58:58 +01:00
|
|
|
snprintf(filename, sizeof(filename)-1, "%s/%02x/%c%c%c/%c%c/%c%c/%s.a%d", cfg->queuedir, cfg->server_id, ptr_arr[i].piler_id[8], ptr_arr[i].piler_id[9], ptr_arr[i].piler_id[10], ptr_arr[i].piler_id[RND_STR_LEN-4], ptr_arr[i].piler_id[RND_STR_LEN-3], ptr_arr[i].piler_id[RND_STR_LEN-2], ptr_arr[i].piler_id[RND_STR_LEN-1], ptr_arr[i].piler_id, ptr_arr[i].attachment_id);
|
2012-12-15 09:57:24 +01:00
|
|
|
|
|
|
|
if(stat(filename, &st)){
|
2013-02-15 20:58:58 +01:00
|
|
|
snprintf(filename, sizeof(filename)-1, "%s/%02x/%c%c/%c%c/%c%c/%s.a%d", cfg->queuedir, cfg->server_id, ptr_arr[i].piler_id[RND_STR_LEN-6], ptr_arr[i].piler_id[RND_STR_LEN-5], ptr_arr[i].piler_id[RND_STR_LEN-4], ptr_arr[i].piler_id[RND_STR_LEN-3], ptr_arr[i].piler_id[RND_STR_LEN-2], ptr_arr[i].piler_id[RND_STR_LEN-1], ptr_arr[i].piler_id, ptr_arr[i].attachment_id);
|
2012-12-15 09:57:24 +01:00
|
|
|
}
|
2012-01-07 16:40:06 +01:00
|
|
|
|
2012-11-03 23:42:36 +01:00
|
|
|
retrieve_file_from_archive(filename, WRITE_TO_STDOUT, NULL, dest, cfg);
|
2012-01-07 16:40:06 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if(buffer){
|
2012-11-03 23:42:36 +01:00
|
|
|
fwrite(buffer, 1, strlen(buffer), dest);
|
2012-01-07 16:40:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
buffer = saved_buffer;
|
|
|
|
free(buffer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|