sanitize error handling in IMAP FETCH response processing

abort on actual error conditions (protocol errors) and downgrade the
rest to warnings.

REFMAIL: 20191102164509.dxayakg3hrmozjnm@carbon
This commit is contained in:
Oswald Buddenhagen 2019-11-11 14:29:42 +01:00
parent b91dd5b3bc
commit a5a8783ea3

View File

@ -968,8 +968,8 @@ parse_date( const char *str )
static int static int
parse_fetch_rsp( imap_store_t *ctx, list_t *list, char *s ATTR_UNUSED ) parse_fetch_rsp( imap_store_t *ctx, list_t *list, char *s ATTR_UNUSED )
{ {
list_t *tmp, *flags; list_t *body = NULL, *tmp, *flags;
char *body = NULL, *tuid = NULL, *msgid = NULL, *ep; char *tuid = NULL, *msgid = NULL, *ep;
imap_message_t *cur; imap_message_t *cur;
msg_data_t *msgdata; msg_data_t *msgdata;
imap_cmd_t *cmdp; imap_cmd_t *cmdp;
@ -986,8 +986,10 @@ parse_fetch_rsp( imap_store_t *ctx, list_t *list, char *s ATTR_UNUSED )
if (is_atom( tmp )) { if (is_atom( tmp )) {
if (!strcmp( "UID", tmp->val )) { if (!strcmp( "UID", tmp->val )) {
tmp = tmp->next; tmp = tmp->next;
if (!is_atom( tmp ) || (uid = strtoul( tmp->val, &ep, 10 ), *ep)) if (!is_atom( tmp ) || (uid = strtoul( tmp->val, &ep, 10 ), *ep)) {
error( "IMAP error: unable to parse UID\n" ); error( "IMAP error: unable to parse UID\n" );
goto ffail;
}
} else if (!strcmp( "FLAGS", tmp->val )) { } else if (!strcmp( "FLAGS", tmp->val )) {
tmp = tmp->next; tmp = tmp->next;
if (is_list( tmp )) { if (is_list( tmp )) {
@ -1007,34 +1009,44 @@ parse_fetch_rsp( imap_store_t *ctx, list_t *list, char *s ATTR_UNUSED )
goto flagok; /* ignore unknown user-defined flags (keywords) */ goto flagok; /* ignore unknown user-defined flags (keywords) */
if (flags->val[0] == '\\' && flags->val[1] == 'X' && flags->val[2] == '-') if (flags->val[0] == '\\' && flags->val[1] == 'X' && flags->val[2] == '-')
goto flagok; /* ignore system flag extensions */ goto flagok; /* ignore system flag extensions */
error( "IMAP warning: unknown system flag %s\n", flags->val ); warn( "IMAP warning: unknown system flag %s\n", flags->val );
} }
flagok: ; flagok: ;
} else } else {
error( "IMAP error: unable to parse FLAGS list\n" ); error( "IMAP error: unable to parse FLAGS list\n" );
goto ffail;
}
} }
status |= M_FLAGS; status |= M_FLAGS;
} else } else {
error( "IMAP error: unable to parse FLAGS\n" ); error( "IMAP error: unable to parse FLAGS\n" );
goto ffail;
}
} else if (!strcmp( "INTERNALDATE", tmp->val )) { } else if (!strcmp( "INTERNALDATE", tmp->val )) {
tmp = tmp->next; tmp = tmp->next;
if (is_atom( tmp )) { if (is_atom( tmp )) {
if ((date = parse_date( tmp->val )) == -1) if ((date = parse_date( tmp->val )) == -1) {
error( "IMAP error: unable to parse INTERNALDATE format\n" ); error( "IMAP error: unable to parse INTERNALDATE format\n" );
} else goto ffail;
}
} else {
error( "IMAP error: unable to parse INTERNALDATE\n" ); error( "IMAP error: unable to parse INTERNALDATE\n" );
goto ffail;
}
} else if (!strcmp( "RFC822.SIZE", tmp->val )) { } else if (!strcmp( "RFC822.SIZE", tmp->val )) {
tmp = tmp->next; tmp = tmp->next;
if (!is_atom( tmp ) || (size = strtoul( tmp->val, &ep, 10 ), *ep)) if (!is_atom( tmp ) || (size = strtoul( tmp->val, &ep, 10 ), *ep)) {
error( "IMAP error: unable to parse RFC822.SIZE\n" ); error( "IMAP error: unable to parse RFC822.SIZE\n" );
goto ffail;
}
} else if (!strcmp( "BODY[]", tmp->val )) { } else if (!strcmp( "BODY[]", tmp->val )) {
tmp = tmp->next; tmp = tmp->next;
if (is_atom( tmp )) { if (is_atom( tmp )) {
body = tmp->val; body = tmp;
tmp->val = NULL; /* don't free together with list */ } else {
size = tmp->len;
} else
error( "IMAP error: unable to parse BODY[]\n" ); error( "IMAP error: unable to parse BODY[]\n" );
goto ffail;
}
} else if (!strcmp( "BODY[HEADER.FIELDS", tmp->val )) { } else if (!strcmp( "BODY[HEADER.FIELDS", tmp->val )) {
tmp = tmp->next; tmp = tmp->next;
if (is_list( tmp )) { if (is_list( tmp )) {
@ -1053,7 +1065,7 @@ parse_fetch_rsp( imap_store_t *ctx, list_t *list, char *s ATTR_UNUSED )
break; break;
if (starts_with_upper( val, len, "X-TUID: ", 8 )) { if (starts_with_upper( val, len, "X-TUID: ", 8 )) {
if (len < 8 + TUIDL) { if (len < 8 + TUIDL) {
error( "IMAP error: malformed X-TUID header (UID %u)\n", uid ); warn( "IMAP warning: malformed X-TUID header (UID %u)\n", uid );
continue; continue;
} }
tuid = val + 8; tuid = val + 8;
@ -1083,6 +1095,7 @@ parse_fetch_rsp( imap_store_t *ctx, list_t *list, char *s ATTR_UNUSED )
} else { } else {
bfail: bfail:
error( "IMAP error: unable to parse BODY[HEADER.FIELDS ...]\n" ); error( "IMAP error: unable to parse BODY[HEADER.FIELDS ...]\n" );
goto ffail;
} }
} }
} }
@ -1104,8 +1117,9 @@ parse_fetch_rsp( imap_store_t *ctx, list_t *list, char *s ATTR_UNUSED )
return LIST_BAD; return LIST_BAD;
gotuid: gotuid:
msgdata = ((imap_cmd_fetch_msg_t *)cmdp)->msg_data; msgdata = ((imap_cmd_fetch_msg_t *)cmdp)->msg_data;
msgdata->data = body; msgdata->data = body->val;
msgdata->len = size; body->val = NULL; // Don't free together with list.
msgdata->len = body->len;
msgdata->date = date; msgdata->date = date;
if (status & M_FLAGS) if (status & M_FLAGS)
msgdata->flags = mask; msgdata->flags = mask;
@ -1127,6 +1141,11 @@ parse_fetch_rsp( imap_store_t *ctx, list_t *list, char *s ATTR_UNUSED )
} }
return LIST_OK; return LIST_OK;
ffail:
free( tuid );
free( msgid );
return LIST_BAD;
} }
static void static void