comparison src/mail/ngx_mail_parse.c @ 7843:b38728495e1a

Mail: IMAP pipelining support. The change is mostly the same as the SMTP one (04e43d03e153 and 3f5d0af4e40a), and ensures that nginx is able to properly handle or reject multiple IMAP commands. The s->cmd field is not really used and set for consistency. Non-synchronizing literals handling in invalid/unknown commands is limited, so when a non-synchronizing literal is detected at the end of a discarded line, the connection is closed.
author Maxim Dounin <mdounin@mdounin.ru>
date Wed, 19 May 2021 03:13:28 +0300
parents 4b15f1b92100
children
comparison
equal deleted inserted replaced
7842:4b15f1b92100 7843:b38728495e1a
229 { 229 {
230 u_char ch, *p, *c, *dst, *src, *end; 230 u_char ch, *p, *c, *dst, *src, *end;
231 ngx_str_t *arg; 231 ngx_str_t *arg;
232 enum { 232 enum {
233 sw_start = 0, 233 sw_start = 0,
234 sw_tag,
235 sw_invalid,
234 sw_spaces_before_command, 236 sw_spaces_before_command,
235 sw_command, 237 sw_command,
236 sw_spaces_before_argument, 238 sw_spaces_before_argument,
237 sw_argument, 239 sw_argument,
238 sw_backslash, 240 sw_backslash,
251 253
252 switch (state) { 254 switch (state) {
253 255
254 /* IMAP tag */ 256 /* IMAP tag */
255 case sw_start: 257 case sw_start:
258 s->tag_start = p;
259 state = sw_tag;
260
261 /* fall through */
262
263 case sw_tag:
256 switch (ch) { 264 switch (ch) {
257 case ' ': 265 case ' ':
258 s->tag.len = p - s->buffer->start + 1; 266 s->tag.len = p - s->tag_start + 1;
259 s->tag.data = s->buffer->start; 267 s->tag.data = s->tag_start;
260 state = sw_spaces_before_command; 268 state = sw_spaces_before_command;
261 break; 269 break;
262 case CR: 270 case CR:
263 s->state = sw_start; 271 case LF:
264 return NGX_MAIL_PARSE_INVALID_COMMAND; 272 goto invalid;
265 case LF:
266 s->state = sw_start;
267 return NGX_MAIL_PARSE_INVALID_COMMAND;
268 default: 273 default:
269 if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z') 274 if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z')
270 && (ch < '0' || ch > '9') && ch != '-' && ch != '.' 275 && (ch < '0' || ch > '9') && ch != '-' && ch != '.'
271 && ch != '_') 276 && ch != '_')
272 { 277 {
273 goto invalid; 278 goto invalid;
274 } 279 }
275 if (p - s->buffer->start > 31) { 280 if (p - s->tag_start > 31) {
276 goto invalid; 281 goto invalid;
277 } 282 }
278 break; 283 break;
279 } 284 }
280 break; 285 break;
281 286
287 case sw_invalid:
288 goto invalid;
289
282 case sw_spaces_before_command: 290 case sw_spaces_before_command:
283 switch (ch) { 291 switch (ch) {
284 case ' ': 292 case ' ':
285 break; 293 break;
286 case CR: 294 case CR:
287 s->state = sw_start; 295 case LF:
288 return NGX_MAIL_PARSE_INVALID_COMMAND; 296 goto invalid;
289 case LF:
290 s->state = sw_start;
291 return NGX_MAIL_PARSE_INVALID_COMMAND;
292 default: 297 default:
293 s->cmd_start = p; 298 s->cmd_start = p;
294 state = sw_command; 299 state = sw_command;
295 break; 300 break;
296 } 301 }
406 411
407 default: 412 default:
408 goto invalid; 413 goto invalid;
409 } 414 }
410 415
416 s->cmd.data = s->cmd_start;
417 s->cmd.len = p - s->cmd_start;
418
411 switch (ch) { 419 switch (ch) {
412 case ' ': 420 case ' ':
413 state = sw_spaces_before_argument; 421 state = sw_spaces_before_argument;
414 break; 422 break;
415 case CR: 423 case CR:
629 637
630 return NGX_OK; 638 return NGX_OK;
631 639
632 invalid: 640 invalid:
633 641
634 s->state = sw_start; 642 s->state = sw_invalid;
635 s->quoted = 0; 643 s->quoted = 0;
636 s->backslash = 0; 644 s->backslash = 0;
637 s->no_sync_literal = 0; 645 s->no_sync_literal = 0;
638 s->literal_len = 0; 646 s->literal_len = 0;
639 647
640 return NGX_MAIL_PARSE_INVALID_COMMAND; 648 /* skip invalid command till LF */
649
650 for ( /* void */ ; p < s->buffer->last; p++) {
651 if (*p == LF) {
652 s->state = sw_start;
653 s->buffer->pos = p + 1;
654
655 /* detect non-synchronizing literals */
656
657 if ((size_t) (p - s->buffer->start) > sizeof("{1+}") - 1) {
658 p--;
659
660 if (*p == CR) {
661 p--;
662 }
663
664 if (*p == '}' && *(p - 1) == '+') {
665 s->quit = 1;
666 }
667 }
668
669 return NGX_MAIL_PARSE_INVALID_COMMAND;
670 }
671 }
672
673 s->buffer->pos = p;
674
675 return NGX_AGAIN;
641 } 676 }
642 677
643 678
644 ngx_int_t 679 ngx_int_t
645 ngx_mail_smtp_parse_command(ngx_mail_session_t *s) 680 ngx_mail_smtp_parse_command(ngx_mail_session_t *s)