"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "src/lib-mail/istream-header-filter.c" between
dovecot-2.3.16.tar.gz and dovecot-2.3.17.tar.gz

About: Dovecot is an IMAP and POP3 server, written with security primarily in mind.

istream-header-filter.c  (dovecot-2.3.16):istream-header-filter.c  (dovecot-2.3.17)
/* Copyright (c) 2003-2018 Dovecot authors, see the included COPYING file */ /* Copyright (c) 2003-2018 Dovecot authors, see the included COPYING file */
#include "lib.h" #include "lib.h"
#include "array.h" #include "array.h"
#include "memarea.h"
#include "sort.h" #include "sort.h"
#include "message-parser.h" #include "message-parser.h"
#include "istream-private.h" #include "istream-private.h"
#include "istream-header-filter.h" #include "istream-header-filter.h"
struct header_filter_istream_snapshot {
struct istream_snapshot snapshot;
struct header_filter_istream *mstream;
buffer_t *hdr_buf;
};
struct header_filter_istream { struct header_filter_istream {
struct istream_private istream; struct istream_private istream;
pool_t pool; pool_t pool;
struct message_header_parser_ctx *hdr_ctx; struct message_header_parser_ctx *hdr_ctx;
const char **headers; const char **headers;
unsigned int headers_count; unsigned int headers_count;
header_filter_callback *callback; header_filter_callback *callback;
skipping to change at line 46 skipping to change at line 53
bool crlf_preserve:1; bool crlf_preserve:1;
bool hide_body:1; bool hide_body:1;
bool add_missing_eoh:1; bool add_missing_eoh:1;
bool end_body_with_lf:1; bool end_body_with_lf:1;
bool last_lf_added:1; bool last_lf_added:1;
bool last_orig_crlf:1; bool last_orig_crlf:1;
bool last_added_newline:1; bool last_added_newline:1;
bool eoh_not_matched:1; bool eoh_not_matched:1;
bool callbacks_called:1; bool callbacks_called:1;
bool prev_matched:1; bool prev_matched:1;
bool snapshot_pending:1;
}; };
header_filter_callback *null_header_filter_callback = NULL; header_filter_callback *null_header_filter_callback = NULL;
static ssize_t i_stream_header_filter_read(struct istream_private *stream); static ssize_t i_stream_header_filter_read(struct istream_private *stream);
static void i_stream_header_filter_destroy(struct iostream_private *stream) static void i_stream_header_filter_destroy(struct iostream_private *stream)
{ {
struct header_filter_istream *mstream = struct header_filter_istream *mstream =
(struct header_filter_istream *)stream; (struct header_filter_istream *)stream;
if (mstream->hdr_ctx != NULL) if (mstream->hdr_ctx != NULL)
message_parse_header_deinit(&mstream->hdr_ctx); message_parse_header_deinit(&mstream->hdr_ctx);
if (array_is_created(&mstream->match_change_lines)) if (array_is_created(&mstream->match_change_lines))
array_free(&mstream->match_change_lines); array_free(&mstream->match_change_lines);
if (!mstream->snapshot_pending)
buffer_free(&mstream->hdr_buf);
else {
/* Clear hdr_buf to make sure
i_stream_header_filter_snapshot_free() frees it. */
mstream->hdr_buf = NULL;
}
pool_unref(&mstream->pool); pool_unref(&mstream->pool);
} }
static ssize_t static ssize_t
read_mixed(struct header_filter_istream *mstream, size_t body_highwater_size) read_mixed(struct header_filter_istream *mstream, size_t body_highwater_size)
{ {
const unsigned char *data; const unsigned char *data;
size_t pos; size_t pos;
ssize_t ret; ssize_t ret;
skipping to change at line 154 skipping to change at line 169
ssize_t ret; ssize_t ret;
size_t pos; size_t pos;
mstream->istream.buffer = buffer_get_data(mstream->hdr_buf, &pos); mstream->istream.buffer = buffer_get_data(mstream->hdr_buf, &pos);
ret = (ssize_t)(pos - mstream->istream.pos - mstream->istream.skip); ret = (ssize_t)(pos - mstream->istream.pos - mstream->istream.skip);
i_assert(ret >= 0); i_assert(ret >= 0);
mstream->istream.pos = pos; mstream->istream.pos = pos;
return ret; return ret;
} }
static void hdr_buf_realloc_if_needed(struct header_filter_istream *mstream)
{
if (!mstream->snapshot_pending)
return;
/* hdr_buf exists in a snapshot. Leave it be and create a copy of it
that we modify. */
buffer_t *old_buf = mstream->hdr_buf;
mstream->hdr_buf = buffer_create_dynamic(default_pool,
I_MAX(1024, old_buf->used));
buffer_append(mstream->hdr_buf, old_buf->data, old_buf->used);
mstream->snapshot_pending = FALSE;
mstream->istream.buffer = mstream->hdr_buf->data;
}
static ssize_t read_header(struct header_filter_istream *mstream) static ssize_t read_header(struct header_filter_istream *mstream)
{ {
struct message_header_line *hdr; struct message_header_line *hdr;
uoff_t highwater_offset; uoff_t highwater_offset;
size_t max_buffer_size; size_t max_buffer_size;
ssize_t ret, ret2; ssize_t ret, ret2;
int hdr_ret; int hdr_ret;
if (mstream->hdr_ctx == NULL) { if (mstream->hdr_ctx == NULL) {
mstream->hdr_ctx = mstream->hdr_ctx =
message_parse_header_init(mstream->istream.parent, message_parse_header_init(mstream->istream.parent,
NULL, 0); NULL, 0);
} }
/* remove skipped data from hdr_buf */ /* remove skipped data from hdr_buf */
hdr_buf_realloc_if_needed(mstream);
buffer_copy(mstream->hdr_buf, 0, buffer_copy(mstream->hdr_buf, 0,
mstream->hdr_buf, mstream->istream.skip, SIZE_MAX); mstream->hdr_buf, mstream->istream.skip, SIZE_MAX);
mstream->istream.pos -= mstream->istream.skip; mstream->istream.pos -= mstream->istream.skip;
mstream->istream.skip = 0; mstream->istream.skip = 0;
buffer_set_used_size(mstream->hdr_buf, mstream->istream.pos); buffer_set_used_size(mstream->hdr_buf, mstream->istream.pos);
if (mstream->header_read) { if (mstream->header_read) {
i_assert(mstream->istream.skip == 0); i_assert(mstream->istream.skip == 0);
highwater_offset = mstream->istream.istream.v_offset + highwater_offset = mstream->istream.istream.v_offset +
skipping to change at line 417 skipping to change at line 449
else if (size > 0) else if (size > 0)
last_lf = data[size-1] == '\n'; last_lf = data[size-1] == '\n';
else else
last_lf = FALSE; last_lf = FALSE;
if (ret == -1 && stream->parent->eof && !last_lf) { if (ret == -1 && stream->parent->eof && !last_lf) {
/* missing LF, need to add it */ /* missing LF, need to add it */
i_assert(!mstream->last_lf_added); i_assert(!mstream->last_lf_added);
i_assert(size == 0 || data[size-1] != '\n'); i_assert(size == 0 || data[size-1] != '\n');
hdr_buf_realloc_if_needed(mstream);
buffer_set_used_size(mstream->hdr_buf, 0); buffer_set_used_size(mstream->hdr_buf, 0);
buffer_append(mstream->hdr_buf, data, size); buffer_append(mstream->hdr_buf, data, size);
if (mstream->crlf) if (mstream->crlf)
buffer_append_c(mstream->hdr_buf, '\r'); buffer_append_c(mstream->hdr_buf, '\r');
buffer_append_c(mstream->hdr_buf, '\n'); buffer_append_c(mstream->hdr_buf, '\n');
mstream->last_lf_offset = last_offset; mstream->last_lf_offset = last_offset;
mstream->last_lf_added = TRUE; mstream->last_lf_added = TRUE;
stream->skip = 0; stream->skip = 0;
stream->pos = mstream->hdr_buf->used; stream->pos = mstream->hdr_buf->used;
skipping to change at line 511 skipping to change at line 544
i_stream_read_memarea(&mstream->istream.istream) != -1) { i_stream_read_memarea(&mstream->istream.istream) != -1) {
pos = i_stream_get_data_size(&mstream->istream.istream); pos = i_stream_get_data_size(&mstream->istream.istream);
i_stream_skip(&mstream->istream.istream, pos); i_stream_skip(&mstream->istream.istream, pos);
} }
return mstream->istream.istream.stream_errno != 0 ? -1 : 0; return mstream->istream.istream.stream_errno != 0 ? -1 : 0;
} }
static void static void
stream_reset_to(struct header_filter_istream *mstream, uoff_t v_offset) stream_reset_to(struct header_filter_istream *mstream, uoff_t v_offset)
{ {
hdr_buf_realloc_if_needed(mstream);
mstream->istream.istream.v_offset = v_offset; mstream->istream.istream.v_offset = v_offset;
mstream->istream.skip = mstream->istream.pos = 0; mstream->istream.skip = mstream->istream.pos = 0;
mstream->istream.buffer = NULL; mstream->istream.buffer = NULL;
buffer_set_used_size(mstream->hdr_buf, 0); buffer_set_used_size(mstream->hdr_buf, 0);
} }
static void i_stream_header_filter_seek(struct istream_private *stream, static void i_stream_header_filter_seek(struct istream_private *stream,
uoff_t v_offset, bool mark ATTR_UNUSED) uoff_t v_offset, bool mark ATTR_UNUSED)
{ {
struct header_filter_istream *mstream = struct header_filter_istream *mstream =
skipping to change at line 554 skipping to change at line 588
if (skip_header(mstream) < 0) if (skip_header(mstream) < 0)
return; return;
stream_reset_to(mstream, v_offset); stream_reset_to(mstream, v_offset);
if (v_offset < mstream->header_size.virtual_size) { if (v_offset < mstream->header_size.virtual_size) {
/* seek into headers. we'll have to re-parse them, use /* seek into headers. we'll have to re-parse them, use
skip_count to set the wanted position */ skip_count to set the wanted position */
i_stream_header_filter_seek_to_header(mstream, v_offset); i_stream_header_filter_seek_to_header(mstream, v_offset);
} else { } else {
/* body */ /* body */
v_offset += mstream->header_size.physical_size - v_offset -= mstream->header_size.virtual_size;
mstream->header_size.virtual_size; v_offset += mstream->header_size.physical_size;
i_stream_seek(stream->parent, i_stream_seek(stream->parent,
stream->parent_start_offset + v_offset); stream->parent_start_offset + v_offset);
} }
} }
static void ATTR_NORETURN static void ATTR_NORETURN
i_stream_header_filter_sync(struct istream_private *stream ATTR_UNUSED) i_stream_header_filter_sync(struct istream_private *stream ATTR_UNUSED)
{ {
i_panic("istream-header-filter sync() not implemented"); i_panic("istream-header-filter sync() not implemented");
} }
skipping to change at line 620 skipping to change at line 654
stream->statbuf.st_size += ret; stream->statbuf.st_size += ret;
} }
stream->statbuf.st_size -= stream->statbuf.st_size -=
(off_t)mstream->header_size.physical_size - (off_t)mstream->header_size.physical_size -
(off_t)mstream->header_size.virtual_size; (off_t)mstream->header_size.virtual_size;
i_stream_seek(&stream->istream, old_offset); i_stream_seek(&stream->istream, old_offset);
return 0; return 0;
} }
static void
i_stream_header_filter_snapshot_free(struct istream_snapshot *_snapshot)
{
struct header_filter_istream_snapshot *snapshot =
container_of(_snapshot, struct header_filter_istream_snapshot, sn
apshot);
if (snapshot->mstream->hdr_buf != snapshot->hdr_buf)
buffer_free(&snapshot->hdr_buf);
else {
i_assert(snapshot->mstream->snapshot_pending);
snapshot->mstream->snapshot_pending = FALSE;
}
i_free(snapshot);
}
static struct istream_snapshot *
i_stream_header_filter_snapshot(struct istream_private *stream,
struct istream_snapshot *prev_snapshot)
{
struct header_filter_istream *mstream =
(struct header_filter_istream *)stream;
struct header_filter_istream_snapshot *snapshot;
if (stream->buffer != mstream->hdr_buf->data) {
/* reading body */
return i_stream_default_snapshot(stream, prev_snapshot);
}
/* snapshot the header buffer */
snapshot = i_new(struct header_filter_istream_snapshot, 1);
snapshot->mstream = mstream;
snapshot->hdr_buf = mstream->hdr_buf;
snapshot->snapshot.free = i_stream_header_filter_snapshot_free;
snapshot->snapshot.prev_snapshot = prev_snapshot;
mstream->snapshot_pending = TRUE;
return &snapshot->snapshot;
}
#undef i_stream_create_header_filter #undef i_stream_create_header_filter
struct istream * struct istream *
i_stream_create_header_filter(struct istream *input, i_stream_create_header_filter(struct istream *input,
enum header_filter_flags flags, enum header_filter_flags flags,
const char *const *headers, const char *const *headers,
unsigned int headers_count, unsigned int headers_count,
header_filter_callback *callback, void *context) header_filter_callback *callback, void *context)
{ {
struct header_filter_istream *mstream; struct header_filter_istream *mstream;
unsigned int i, j; unsigned int i, j;
int ret; int ret;
i_assert((flags & (HEADER_FILTER_INCLUDE|HEADER_FILTER_EXCLUDE)) != 0); i_assert((flags & (HEADER_FILTER_INCLUDE|HEADER_FILTER_EXCLUDE)) != 0);
mstream = i_new(struct header_filter_istream, 1); mstream = i_new(struct header_filter_istream, 1);
mstream->pool = pool_alloconly_create(MEMPOOL_GROWING mstream->pool = pool_alloconly_create(MEMPOOL_GROWING
"header filter stream", 4096); "header filter stream", 256);
mstream->istream.max_buffer_size = input->real_stream->max_buffer_size; mstream->istream.max_buffer_size = input->real_stream->max_buffer_size;
mstream->headers = headers_count == 0 ? NULL : mstream->headers = headers_count == 0 ? NULL :
p_new(mstream->pool, const char *, headers_count); p_new(mstream->pool, const char *, headers_count);
for (i = j = 0; i < headers_count; i++) { for (i = j = 0; i < headers_count; i++) {
ret = j == 0 ? -1 : ret = j == 0 ? -1 :
strcasecmp(mstream->headers[j-1], headers[i]); strcasecmp(mstream->headers[j-1], headers[i]);
if (ret == 0) { if (ret == 0) {
/* drop duplicate */ /* drop duplicate */
continue; continue;
} }
i_assert(ret < 0); i_assert(ret < 0);
mstream->headers[j++] = p_strdup(mstream->pool, headers[i]); mstream->headers[j++] = p_strdup(mstream->pool, headers[i]);
} }
mstream->headers_count = j; mstream->headers_count = j;
mstream->hdr_buf = buffer_create_dynamic(mstream->pool, 1024); mstream->hdr_buf = buffer_create_dynamic(default_pool, 1024);
mstream->callback = callback; mstream->callback = callback;
mstream->context = context; mstream->context = context;
mstream->exclude = (flags & HEADER_FILTER_EXCLUDE) != 0; mstream->exclude = (flags & HEADER_FILTER_EXCLUDE) != 0;
if ((flags & HEADER_FILTER_CRLF_PRESERVE) != 0) if ((flags & HEADER_FILTER_CRLF_PRESERVE) != 0)
mstream->crlf_preserve = TRUE; mstream->crlf_preserve = TRUE;
else if ((flags & HEADER_FILTER_NO_CR) != 0) else if ((flags & HEADER_FILTER_NO_CR) != 0)
mstream->crlf = FALSE; mstream->crlf = FALSE;
else else
mstream->crlf = TRUE; mstream->crlf = TRUE;
skipping to change at line 675 skipping to change at line 747
mstream->end_body_with_lf = mstream->end_body_with_lf =
(flags & HEADER_FILTER_END_BODY_WITH_LF) != 0; (flags & HEADER_FILTER_END_BODY_WITH_LF) != 0;
mstream->last_lf_offset = UOFF_T_MAX; mstream->last_lf_offset = UOFF_T_MAX;
mstream->last_added_newline = TRUE; mstream->last_added_newline = TRUE;
mstream->istream.iostream.destroy = i_stream_header_filter_destroy; mstream->istream.iostream.destroy = i_stream_header_filter_destroy;
mstream->istream.read = i_stream_header_filter_read; mstream->istream.read = i_stream_header_filter_read;
mstream->istream.seek = i_stream_header_filter_seek; mstream->istream.seek = i_stream_header_filter_seek;
mstream->istream.sync = i_stream_header_filter_sync; mstream->istream.sync = i_stream_header_filter_sync;
mstream->istream.stat = i_stream_header_filter_stat; mstream->istream.stat = i_stream_header_filter_stat;
mstream->istream.snapshot = i_stream_header_filter_snapshot;
mstream->istream.istream.readable_fd = FALSE; mstream->istream.istream.readable_fd = FALSE;
mstream->istream.istream.blocking = input->blocking; mstream->istream.istream.blocking = input->blocking;
mstream->istream.istream.seekable = input->seekable; mstream->istream.istream.seekable = input->seekable;
return i_stream_create(&mstream->istream, input, -1, 0); return i_stream_create(&mstream->istream, input, -1, 0);
} }
void i_stream_header_filter_add(struct header_filter_istream *input, void i_stream_header_filter_add(struct header_filter_istream *input,
const void *data, size_t size) const void *data, size_t size)
{ {
hdr_buf_realloc_if_needed(input);
buffer_append(input->hdr_buf, data, size); buffer_append(input->hdr_buf, data, size);
input->headers_edited = TRUE; input->headers_edited = TRUE;
} }
 End of changes. 14 change blocks. 
4 lines changed or deleted 79 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)