Skip to content

Commit

Permalink
lib-mail: Change rfc822_parse_content_param() API to allow NULs in value
Browse files Browse the repository at this point in the history
This was the only function in rfc822-parser.h that wasn't NUL-safe.
This won't fix anything, but it makes the rfc822-parser.h API fully
consistent with the NUL handling.

Normally rfc2231_parse() should be called instead of calling
rfc822_parse_content_param() directly, so this shouldn't break any plugins.
  • Loading branch information
sirainen committed Aug 30, 2018
1 parent 888cfdc commit 6cc952b
Show file tree
Hide file tree
Showing 4 changed files with 23 additions and 24 deletions.
11 changes: 6 additions & 5 deletions src/lib-mail/rfc2231-parser.c
Expand Up @@ -43,7 +43,7 @@ int rfc2231_parse(struct rfc822_parser_context *ctx,
ARRAY(struct rfc2231_parameter) rfc2231_params_arr;
struct rfc2231_parameter rfc2231_param;
const struct rfc2231_parameter *rfc2231_params;
const char *key, *value, *p, *p2;
const char *key, *p, *p2;
string_t *str;
unsigned int i, j, count, next, next_idx;
bool ok, have_extended, broken = FALSE;
Expand All @@ -55,7 +55,8 @@ int rfc2231_parse(struct rfc822_parser_context *ctx,
i_zero(&rfc2231_param);
t_array_init(&result, 8);
t_array_init(&rfc2231_params_arr, 8);
while ((ret = rfc822_parse_content_param(ctx, &key, &value)) != 0) {
str = t_str_new(64);
while ((ret = rfc822_parse_content_param(ctx, &key, str)) != 0) {
if (ret < 0) {
/* try to continue anyway.. */
broken = TRUE;
Expand Down Expand Up @@ -85,12 +86,13 @@ int rfc2231_parse(struct rfc822_parser_context *ctx,
p = NULL;
else {
rfc2231_param.key = t_strdup_until(key, p2);
rfc2231_param.value = value;
rfc2231_param.value = t_strdup(str_c(str));
array_append(&rfc2231_params_arr,
&rfc2231_param, 1);
}
}
if (p == NULL) {
const char *value = t_strdup(str_c(str));
array_append(&result, &key, 1);
array_append(&result, &value, 1);
}
Expand All @@ -111,7 +113,6 @@ int rfc2231_parse(struct rfc822_parser_context *ctx,
/* keys are now sorted primarily by their name and secondarily by
their index. If any indexes are missing, fallback to assuming
these aren't RFC 2231 encoded parameters. */
str = t_str_new(64);
for (i = 0; i < count; i = next) {
ok = TRUE;
have_extended = FALSE;
Expand Down Expand Up @@ -160,7 +161,7 @@ int rfc2231_parse(struct rfc822_parser_context *ctx,
key = rfc2231_params[i].key;
if (have_extended)
key = t_strconcat(key, "*", NULL);
value = t_strdup(str_c(str));
const char *value = t_strdup(str_c(str));
array_append(&result, &key, 1);
array_append(&result, &value, 1);
}
Expand Down
22 changes: 9 additions & 13 deletions src/lib-mail/rfc822-parser.c
Expand Up @@ -375,10 +375,9 @@ int rfc822_parse_content_type(struct rfc822_parser_context *ctx, string_t *str)
}

int rfc822_parse_content_param(struct rfc822_parser_context *ctx,
const char **key_r, const char **value_r)
const char **key_r, string_t *value)
{
string_t *tmp;
size_t value_pos;
string_t *key;
int ret;

/* .. := *(";" parameter)
Expand All @@ -387,7 +386,7 @@ int rfc822_parse_content_param(struct rfc822_parser_context *ctx,
value := token / quoted-string
*/
*key_r = NULL;
*value_r = NULL;
str_truncate(value, 0);

if (ctx->data >= ctx->end)
return 0;
Expand All @@ -398,11 +397,9 @@ int rfc822_parse_content_param(struct rfc822_parser_context *ctx,
if (rfc822_skip_lwsp(ctx) <= 0)
return -1;

tmp = t_str_new(64);
if (rfc822_parse_mime_token(ctx, tmp) <= 0)
key = t_str_new(64);
if (rfc822_parse_mime_token(ctx, key) <= 0)
return -1;
str_append_c(tmp, '\0');
value_pos = str_len(tmp);

if (*ctx->data != '=')
return -1;
Expand All @@ -411,21 +408,20 @@ int rfc822_parse_content_param(struct rfc822_parser_context *ctx,
if ((ret = rfc822_skip_lwsp(ctx)) <= 0) {
/* broken / no value */
} else if (*ctx->data == '"') {
ret = rfc822_parse_quoted_string(ctx, tmp);
ret = rfc822_parse_quoted_string(ctx, value);
} else if (ctx->data < ctx->end && *ctx->data == '=') {
/* workaround for broken input:
name==?utf-8?b?...?= */
while (ctx->data < ctx->end && *ctx->data != ';' &&
*ctx->data != ' ' && *ctx->data != '\t' &&
*ctx->data != '\r' && *ctx->data != '\n') {
str_append_c(tmp, *ctx->data);
str_append_c(value, *ctx->data);
ctx->data++;
}
} else {
ret = rfc822_parse_mime_token(ctx, tmp);
ret = rfc822_parse_mime_token(ctx, value);
}

*key_r = str_c(tmp);
*value_r = *key_r + value_pos;
*key_r = str_c(key);
return ret < 0 ? -1 : 1;
}
7 changes: 4 additions & 3 deletions src/lib-mail/rfc822-parser.h
Expand Up @@ -54,9 +54,10 @@ int rfc822_parse_domain(struct rfc822_parser_context *ctx, string_t *str);
/* Parse Content-Type header's type/subtype. */
int rfc822_parse_content_type(struct rfc822_parser_context *ctx, string_t *str);
/* For Content-Type style parameter parsing. Expect ";" key "=" value.
value is unescaped if needed. The returned strings are allocated from data
stack. Returns 1 = key/value set, 0 = no more data, -1 = invalid input. */
value is unescaped if needed. The returned key is allocated from data
stack. The value string is truncated for each call. Returns 1 = key/value
set, 0 = no more data, -1 = invalid input. */
int rfc822_parse_content_param(struct rfc822_parser_context *ctx,
const char **key_r, const char **value_r);
const char **key_r, string_t *value);

#endif
7 changes: 4 additions & 3 deletions src/lib-mail/test-rfc822-parser.c
Expand Up @@ -49,16 +49,17 @@ static void test_rfc822_parse_content_param(void)
{ "key2", " \"(),/:;<=>?@[\\]" }
};
struct rfc822_parser_context parser;
const char *key, *value;
const char *key;
string_t *value = t_str_new(64);
unsigned int i = 0;
int ret;

test_begin("rfc822 parse content param");
rfc822_parser_init(&parser, (const void *)input, strlen(input), NULL);
while ((ret = rfc822_parse_content_param(&parser, &key, &value)) > 0 &&
while ((ret = rfc822_parse_content_param(&parser, &key, value)) > 0 &&
i < N_ELEMENTS(output)) {
test_assert_idx(strcmp(output[i].key, key) == 0, i);
test_assert_idx(strcmp(output[i].value, value) == 0, i);
test_assert_idx(strcmp(output[i].value, str_c(value)) == 0, i);
i++;
}
rfc822_parser_deinit(&parser);
Expand Down

0 comments on commit 6cc952b

Please sign in to comment.