message-header-parser.c (dovecot-2.3.16) | : | message-header-parser.c (dovecot-2.3.17) | ||
---|---|---|---|---|
/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */ | /* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */ | |||
#include "lib.h" | #include "lib.h" | |||
#include "buffer.h" | #include "buffer.h" | |||
#include "istream.h" | #include "istream.h" | |||
#include "str.h" | #include "str.h" | |||
#include "strfuncs.h" | ||||
#include "unichar.h" | #include "unichar.h" | |||
#include "message-size.h" | #include "message-size.h" | |||
#include "message-header-parser.h" | #include "message-header-parser.h" | |||
/* RFC 5322 2.1.1 and 2.2 */ | ||||
#define MESSAGE_HEADER_NAME_MAX_LEN 1000 | ||||
struct message_header_parser_ctx { | struct message_header_parser_ctx { | |||
struct message_header_line line; | struct message_header_line line; | |||
struct istream *input; | struct istream *input; | |||
struct message_size *hdr_size; | struct message_size *hdr_size; | |||
string_t *name; | string_t *name; | |||
buffer_t *value_buf; | buffer_t *value_buf; | |||
enum message_header_parser_flags flags; | enum message_header_parser_flags flags; | |||
skipping to change at line 265 | skipping to change at line 269 | |||
line->eoh = TRUE; | line->eoh = TRUE; | |||
line->name_len = line->value_len = line->full_value_len = 0; | line->name_len = line->value_len = line->full_value_len = 0; | |||
line->name = ""; line->value = line->full_value = NULL; | line->name = ""; line->value = line->full_value = NULL; | |||
line->middle = NULL; line->middle_len = 0; | line->middle = NULL; line->middle_len = 0; | |||
line->full_value_offset = line->name_offset; | line->full_value_offset = line->name_offset; | |||
line->continues = FALSE; | line->continues = FALSE; | |||
} else if (line->continued) { | } else if (line->continued) { | |||
line->value = msg; | line->value = msg; | |||
line->value_len = size; | line->value_len = size; | |||
} else if (colon_pos == UINT_MAX) { | } else if (colon_pos == UINT_MAX) { | |||
/* missing ':', assume the whole line is name */ | /* missing ':', assume the whole line is value */ | |||
line->value = NULL; | line->value = msg; | |||
line->value_len = 0; | line->value_len = size; | |||
line->full_value_offset = line->name_offset; | ||||
str_truncate(ctx->name, 0); | ||||
buffer_append(ctx->name, msg, size); | ||||
line->name = str_c(ctx->name); | ||||
line->name_len = str_len(ctx->name); | ||||
line->middle = NULL; | line->name = ""; | |||
line->name_len = 0; | ||||
line->middle = uchar_empty_ptr; | ||||
line->middle_len = 0; | line->middle_len = 0; | |||
} else { | } else { | |||
size_t pos; | size_t pos; | |||
line->value = msg + colon_pos+1; | line->value = msg + colon_pos+1; | |||
line->value_len = size - colon_pos - 1; | line->value_len = size - colon_pos - 1; | |||
if ((ctx->flags & MESSAGE_HEADER_PARSER_FLAG_SKIP_INITIAL_LWSP) ! = 0) { | if ((ctx->flags & MESSAGE_HEADER_PARSER_FLAG_SKIP_INITIAL_LWSP) ! = 0) { | |||
/* get value. skip all LWSP after ':'. Note that | /* get value. skip all LWSP after ':'. Note that | |||
RFC2822 doesn't say we should, but history behind | RFC2822 doesn't say we should, but history behind | |||
it.. | it.. | |||
skipping to change at line 312 | skipping to change at line 315 | |||
} | } | |||
line->value += pos; | line->value += pos; | |||
line->value_len -= pos; | line->value_len -= pos; | |||
line->full_value_offset += pos; | line->full_value_offset += pos; | |||
/* get name, skip LWSP before ':' */ | /* get name, skip LWSP before ':' */ | |||
while (colon_pos > 0 && IS_LWSP(msg[colon_pos-1])) | while (colon_pos > 0 && IS_LWSP(msg[colon_pos-1])) | |||
colon_pos--; | colon_pos--; | |||
str_truncate(ctx->name, 0); | /* Treat overlong header names as if the full header line was | |||
/* use buffer_append() so the name won't be truncated if there | a value. Callers can usually handle large values better than | |||
are NULs. */ | large names. */ | |||
buffer_append(ctx->name, msg, colon_pos); | if (colon_pos > MESSAGE_HEADER_NAME_MAX_LEN) { | |||
str_append_c(ctx->name, '\0'); | line->name = ""; | |||
line->name_len = 0; | ||||
/* keep middle stored also in ctx->name so it's available | line->middle = uchar_empty_ptr; | |||
with use_full_value */ | line->middle_len = 0; | |||
line->middle = msg + colon_pos; | line->value = msg; | |||
line->middle_len = (size_t)(line->value - line->middle); | line->value_len = size; | |||
str_append_data(ctx->name, line->middle, line->middle_len); | line->full_value_offset = line->name_offset; | |||
} else { | ||||
line->name = str_c(ctx->name); | str_truncate(ctx->name, 0); | |||
line->name_len = colon_pos; | /* use buffer_append() so the name won't be truncated if | |||
line->middle = str_data(ctx->name) + line->name_len + 1; | there | |||
are NULs. */ | ||||
buffer_append(ctx->name, msg, colon_pos); | ||||
str_append_c(ctx->name, '\0'); | ||||
/* keep middle stored also in ctx->name so it's available | ||||
with use_full_value */ | ||||
line->middle = msg + colon_pos; | ||||
line->middle_len = (size_t)(line->value - line->middle); | ||||
str_append_data(ctx->name, line->middle, line->middle_len | ||||
); | ||||
line->name = str_c(ctx->name); | ||||
line->name_len = colon_pos; | ||||
line->middle = str_data(ctx->name) + line->name_len + 1; | ||||
} | ||||
} | } | |||
if (!line->continued) { | if (!line->continued) { | |||
/* first header line. make a copy of the line since we can't | /* first header line. make a copy of the line since we can't | |||
really trust input stream not to lose it. */ | really trust input stream not to lose it. */ | |||
buffer_append(ctx->value_buf, line->value, line->value_len); | buffer_append(ctx->value_buf, line->value, line->value_len); | |||
line->value = line->full_value = ctx->value_buf->data; | line->value = line->full_value = ctx->value_buf->data; | |||
line->full_value_len = line->value_len; | line->full_value_len = line->value_len; | |||
} else if (line->use_full_value) { | } else if (line->use_full_value) { | |||
/* continue saving the full value. */ | /* continue saving the full value. */ | |||
skipping to change at line 437 | skipping to change at line 453 | |||
rare so keep it simple */ | rare so keep it simple */ | |||
string_t *str = str_new(pool, size+2); | string_t *str = str_new(pool, size+2); | |||
for (size_t i = 0; i < size; i++) { | for (size_t i = 0; i < size; i++) { | |||
if (data[i] != '\0') | if (data[i] != '\0') | |||
str_append_c(str, data[i]); | str_append_c(str, data[i]); | |||
else | else | |||
str_append(str, UNICODE_REPLACEMENT_CHAR_UTF8); | str_append(str, UNICODE_REPLACEMENT_CHAR_UTF8); | |||
} | } | |||
return str_c(str); | return str_c(str); | |||
} | } | |||
bool message_header_name_is_valid(const char *name) | ||||
{ | ||||
/* | ||||
field-name = 1*ftext | ||||
ftext = %d33-57 / ; Printable US-ASCII | ||||
%d59-126 ; characters not including | ||||
; ":". | ||||
*/ | ||||
for (unsigned int i = 0; name[i] != '\0'; i++) { | ||||
unsigned char c = name[i]; | ||||
if (c >= 33 && c <= 57) { | ||||
/* before ":" */ | ||||
} else if (c >= 59 && c <= 126) { | ||||
/* after ":" */ | ||||
} else { | ||||
return FALSE; | ||||
} | ||||
} | ||||
return TRUE; | ||||
} | ||||
End of changes. 6 change blocks. | ||||
24 lines changed or deleted | 42 lines changed or added |