3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Nginx, Inc.
8 #include <ngx_config.h>
10 #include <ngx_event.h>
12 #include <ngx_mail_pop3_module.h>
13 #include <ngx_mail_imap_module.h>
14 #include <ngx_mail_smtp_module.h>
18 ngx_mail_pop3_parse_command(ngx_mail_session_t
*s
)
20 u_char ch
, *p
, *c
, c0
, c1
, c2
, c3
;
24 sw_spaces_before_argument
,
31 for (p
= s
->buffer
->pos
; p
< s
->buffer
->last
; p
++) {
38 if (ch
== ' ' || ch
== CR
|| ch
== LF
) {
43 c0
= ngx_toupper(c
[0]);
44 c1
= ngx_toupper(c
[1]);
45 c2
= ngx_toupper(c
[2]);
46 c3
= ngx_toupper(c
[3]);
48 if (c0
== 'U' && c1
== 'S' && c2
== 'E' && c3
== 'R')
50 s
->command
= NGX_POP3_USER
;
52 } else if (c0
== 'P' && c1
== 'A' && c2
== 'S' && c3
== 'S')
54 s
->command
= NGX_POP3_PASS
;
56 } else if (c0
== 'A' && c1
== 'P' && c2
== 'O' && c3
== 'P')
58 s
->command
= NGX_POP3_APOP
;
60 } else if (c0
== 'Q' && c1
== 'U' && c2
== 'I' && c3
== 'T')
62 s
->command
= NGX_POP3_QUIT
;
64 } else if (c0
== 'C' && c1
== 'A' && c2
== 'P' && c3
== 'A')
66 s
->command
= NGX_POP3_CAPA
;
68 } else if (c0
== 'A' && c1
== 'U' && c2
== 'T' && c3
== 'H')
70 s
->command
= NGX_POP3_AUTH
;
72 } else if (c0
== 'N' && c1
== 'O' && c2
== 'O' && c3
== 'P')
74 s
->command
= NGX_POP3_NOOP
;
76 } else if (c0
== 'S' && c1
== 'T' && c2
== 'L' && c3
== 'S')
78 s
->command
= NGX_POP3_STLS
;
90 state
= sw_spaces_before_argument
;
93 state
= sw_almost_done
;
101 if ((ch
< 'A' || ch
> 'Z') && (ch
< 'a' || ch
> 'z')) {
107 case sw_spaces_before_argument
:
112 state
= sw_almost_done
;
119 if (s
->args
.nelts
<= 2) {
134 * the space should be considered as part of the at username
135 * or password, but not of argument in other commands
138 if (s
->command
== NGX_POP3_USER
139 || s
->command
== NGX_POP3_PASS
)
148 arg
= ngx_array_push(&s
->args
);
152 arg
->len
= p
- s
->arg_start
;
153 arg
->data
= s
->arg_start
;
158 state
= sw_spaces_before_argument
;
161 state
= sw_almost_done
;
190 s
->buffer
->pos
= p
+ 1;
193 arg
= ngx_array_push(&s
->args
);
197 arg
->len
= s
->arg_end
- s
->arg_start
;
198 arg
->data
= s
->arg_start
;
202 s
->state
= (s
->command
!= NGX_POP3_AUTH
) ? sw_start
: sw_argument
;
211 return NGX_MAIL_PARSE_INVALID_COMMAND
;
216 ngx_mail_imap_parse_command(ngx_mail_session_t
*s
)
222 sw_spaces_before_command
,
224 sw_spaces_before_argument
,
228 sw_no_sync_literal_argument
,
229 sw_start_literal_argument
,
231 sw_end_literal_argument
,
237 for (p
= s
->buffer
->pos
; p
< s
->buffer
->last
; p
++) {
246 s
->tag
.len
= p
- s
->buffer
->start
+ 1;
247 s
->tag
.data
= s
->buffer
->start
;
248 state
= sw_spaces_before_command
;
252 return NGX_MAIL_PARSE_INVALID_COMMAND
;
255 return NGX_MAIL_PARSE_INVALID_COMMAND
;
259 case sw_spaces_before_command
:
265 return NGX_MAIL_PARSE_INVALID_COMMAND
;
268 return NGX_MAIL_PARSE_INVALID_COMMAND
;
277 if (ch
== ' ' || ch
== CR
|| ch
== LF
) {
284 if ((c
[0] == 'N' || c
[0] == 'n')
285 && (c
[1] == 'O'|| c
[1] == 'o')
286 && (c
[2] == 'O'|| c
[2] == 'o')
287 && (c
[3] == 'P'|| c
[3] == 'p'))
289 s
->command
= NGX_IMAP_NOOP
;
297 if ((c
[0] == 'L'|| c
[0] == 'l')
298 && (c
[1] == 'O'|| c
[1] == 'o')
299 && (c
[2] == 'G'|| c
[2] == 'g')
300 && (c
[3] == 'I'|| c
[3] == 'i')
301 && (c
[4] == 'N'|| c
[4] == 'n'))
303 s
->command
= NGX_IMAP_LOGIN
;
311 if ((c
[0] == 'L'|| c
[0] == 'l')
312 && (c
[1] == 'O'|| c
[1] == 'o')
313 && (c
[2] == 'G'|| c
[2] == 'g')
314 && (c
[3] == 'O'|| c
[3] == 'o')
315 && (c
[4] == 'U'|| c
[4] == 'u')
316 && (c
[5] == 'T'|| c
[5] == 't'))
318 s
->command
= NGX_IMAP_LOGOUT
;
327 if ((c
[0] == 'S'|| c
[0] == 's')
328 && (c
[1] == 'T'|| c
[1] == 't')
329 && (c
[2] == 'A'|| c
[2] == 'a')
330 && (c
[3] == 'R'|| c
[3] == 'r')
331 && (c
[4] == 'T'|| c
[4] == 't')
332 && (c
[5] == 'T'|| c
[5] == 't')
333 && (c
[6] == 'L'|| c
[6] == 'l')
334 && (c
[7] == 'S'|| c
[7] == 's'))
336 s
->command
= NGX_IMAP_STARTTLS
;
345 if ((c
[0] == 'C'|| c
[0] == 'c')
346 && (c
[1] == 'A'|| c
[1] == 'a')
347 && (c
[2] == 'P'|| c
[2] == 'p')
348 && (c
[3] == 'A'|| c
[3] == 'a')
349 && (c
[4] == 'B'|| c
[4] == 'b')
350 && (c
[5] == 'I'|| c
[5] == 'i')
351 && (c
[6] == 'L'|| c
[6] == 'l')
352 && (c
[7] == 'I'|| c
[7] == 'i')
353 && (c
[8] == 'T'|| c
[8] == 't')
354 && (c
[9] == 'Y'|| c
[9] == 'y'))
356 s
->command
= NGX_IMAP_CAPABILITY
;
364 if ((c
[0] == 'A'|| c
[0] == 'a')
365 && (c
[1] == 'U'|| c
[1] == 'u')
366 && (c
[2] == 'T'|| c
[2] == 't')
367 && (c
[3] == 'H'|| c
[3] == 'h')
368 && (c
[4] == 'E'|| c
[4] == 'e')
369 && (c
[5] == 'N'|| c
[5] == 'n')
370 && (c
[6] == 'T'|| c
[6] == 't')
371 && (c
[7] == 'I'|| c
[7] == 'i')
372 && (c
[8] == 'C'|| c
[8] == 'c')
373 && (c
[9] == 'A'|| c
[9] == 'a')
374 && (c
[10] == 'T'|| c
[10] == 't')
375 && (c
[11] == 'E'|| c
[11] == 'e'))
377 s
->command
= NGX_IMAP_AUTHENTICATE
;
390 state
= sw_spaces_before_argument
;
393 state
= sw_almost_done
;
401 if ((ch
< 'A' || ch
> 'Z') && (ch
< 'a' || ch
> 'z')) {
407 case sw_spaces_before_argument
:
412 state
= sw_almost_done
;
419 if (s
->args
.nelts
<= 2) {
421 s
->arg_start
= p
+ 1;
427 if (s
->args
.nelts
<= 2) {
433 if (s
->args
.nelts
<= 2) {
443 if (ch
== ' ' && s
->quoted
) {
457 arg
= ngx_array_push(&s
->args
);
461 arg
->len
= p
- s
->arg_start
;
462 arg
->data
= s
->arg_start
;
468 state
= sw_spaces_before_argument
;
471 state
= sw_almost_done
;
480 state
= sw_backslash
;
497 if (ch
>= '0' && ch
<= '9') {
498 s
->literal_len
= s
->literal_len
* 10 + (ch
- '0');
502 state
= sw_start_literal_argument
;
506 state
= sw_no_sync_literal_argument
;
511 case sw_no_sync_literal_argument
:
513 s
->no_sync_literal
= 1;
514 state
= sw_start_literal_argument
;
519 case sw_start_literal_argument
:
524 s
->buffer
->pos
= p
+ 1;
525 s
->arg_start
= p
+ 1;
526 if (s
->no_sync_literal
== 0) {
527 s
->state
= sw_literal_argument
;
528 return NGX_IMAP_NEXT
;
530 state
= sw_literal_argument
;
531 s
->no_sync_literal
= 0;
538 case sw_literal_argument
:
539 if (s
->literal_len
&& --s
->literal_len
) {
543 arg
= ngx_array_push(&s
->args
);
547 arg
->len
= p
+ 1 - s
->arg_start
;
548 arg
->data
= s
->arg_start
;
550 state
= sw_end_literal_argument
;
554 case sw_end_literal_argument
:
557 if (s
->args
.nelts
<= 2) {
563 state
= sw_almost_done
;
568 state
= sw_spaces_before_argument
;
590 s
->buffer
->pos
= p
+ 1;
593 arg
= ngx_array_push(&s
->args
);
597 arg
->len
= s
->arg_end
- s
->arg_start
;
598 arg
->data
= s
->arg_start
;
603 s
->no_sync_literal
= 0;
607 s
->state
= (s
->command
!= NGX_IMAP_AUTHENTICATE
) ? sw_start
: sw_argument
;
615 s
->no_sync_literal
= 0;
618 return NGX_MAIL_PARSE_INVALID_COMMAND
;
623 ngx_mail_smtp_parse_command(ngx_mail_session_t
*s
)
625 u_char ch
, *p
, *c
, c0
, c1
, c2
, c3
;
629 sw_spaces_before_argument
,
636 for (p
= s
->buffer
->pos
; p
< s
->buffer
->last
; p
++) {
643 if (ch
== ' ' || ch
== CR
|| ch
== LF
) {
644 c
= s
->buffer
->start
;
648 c0
= ngx_toupper(c
[0]);
649 c1
= ngx_toupper(c
[1]);
650 c2
= ngx_toupper(c
[2]);
651 c3
= ngx_toupper(c
[3]);
653 if (c0
== 'H' && c1
== 'E' && c2
== 'L' && c3
== 'O')
655 s
->command
= NGX_SMTP_HELO
;
657 } else if (c0
== 'E' && c1
== 'H' && c2
== 'L' && c3
== 'O')
659 s
->command
= NGX_SMTP_EHLO
;
661 } else if (c0
== 'Q' && c1
== 'U' && c2
== 'I' && c3
== 'T')
663 s
->command
= NGX_SMTP_QUIT
;
665 } else if (c0
== 'A' && c1
== 'U' && c2
== 'T' && c3
== 'H')
667 s
->command
= NGX_SMTP_AUTH
;
669 } else if (c0
== 'N' && c1
== 'O' && c2
== 'O' && c3
== 'P')
671 s
->command
= NGX_SMTP_NOOP
;
673 } else if (c0
== 'M' && c1
== 'A' && c2
== 'I' && c3
== 'L')
675 s
->command
= NGX_SMTP_MAIL
;
677 } else if (c0
== 'R' && c1
== 'S' && c2
== 'E' && c3
== 'T')
679 s
->command
= NGX_SMTP_RSET
;
681 } else if (c0
== 'R' && c1
== 'C' && c2
== 'P' && c3
== 'T')
683 s
->command
= NGX_SMTP_RCPT
;
685 } else if (c0
== 'V' && c1
== 'R' && c2
== 'F' && c3
== 'Y')
687 s
->command
= NGX_SMTP_VRFY
;
689 } else if (c0
== 'E' && c1
== 'X' && c2
== 'P' && c3
== 'N')
691 s
->command
= NGX_SMTP_EXPN
;
693 } else if (c0
== 'H' && c1
== 'E' && c2
== 'L' && c3
== 'P')
695 s
->command
= NGX_SMTP_HELP
;
701 } else if (p
- c
== 8) {
703 if ((c
[0] == 'S'|| c
[0] == 's')
704 && (c
[1] == 'T'|| c
[1] == 't')
705 && (c
[2] == 'A'|| c
[2] == 'a')
706 && (c
[3] == 'R'|| c
[3] == 'r')
707 && (c
[4] == 'T'|| c
[4] == 't')
708 && (c
[5] == 'T'|| c
[5] == 't')
709 && (c
[6] == 'L'|| c
[6] == 'l')
710 && (c
[7] == 'S'|| c
[7] == 's'))
712 s
->command
= NGX_SMTP_STARTTLS
;
724 state
= sw_spaces_before_argument
;
727 state
= sw_almost_done
;
735 if ((ch
< 'A' || ch
> 'Z') && (ch
< 'a' || ch
> 'z')) {
741 case sw_spaces_before_argument
:
746 state
= sw_almost_done
;
753 if (s
->args
.nelts
<= 10) {
767 arg
= ngx_array_push(&s
->args
);
771 arg
->len
= p
- s
->arg_start
;
772 arg
->data
= s
->arg_start
;
777 state
= sw_spaces_before_argument
;
780 state
= sw_almost_done
;
809 s
->buffer
->pos
= p
+ 1;
812 arg
= ngx_array_push(&s
->args
);
816 arg
->len
= s
->arg_end
- s
->arg_start
;
817 arg
->data
= s
->arg_start
;
821 s
->state
= (s
->command
!= NGX_SMTP_AUTH
) ? sw_start
: sw_argument
;
830 return NGX_MAIL_PARSE_INVALID_COMMAND
;
835 ngx_mail_auth_parse(ngx_mail_session_t
*s
, ngx_connection_t
*c
)
840 if (ngx_mail_starttls_only(s
, c
)) {
841 return NGX_MAIL_PARSE_INVALID_COMMAND
;
847 if (arg
[0].len
== 5) {
849 if (ngx_strncasecmp(arg
[0].data
, (u_char
*) "LOGIN", 5) == 0) {
851 if (s
->args
.nelts
== 1) {
852 return NGX_MAIL_AUTH_LOGIN
;
855 if (s
->args
.nelts
== 2) {
856 return NGX_MAIL_AUTH_LOGIN_USERNAME
;
859 return NGX_MAIL_PARSE_INVALID_COMMAND
;
862 if (ngx_strncasecmp(arg
[0].data
, (u_char
*) "PLAIN", 5) == 0) {
864 if (s
->args
.nelts
== 1) {
865 return NGX_MAIL_AUTH_PLAIN
;
868 if (s
->args
.nelts
== 2) {
869 return ngx_mail_auth_plain(s
, c
, 1);
873 return NGX_MAIL_PARSE_INVALID_COMMAND
;
876 if (arg
[0].len
== 8) {
878 if (s
->args
.nelts
!= 1) {
879 return NGX_MAIL_PARSE_INVALID_COMMAND
;
882 if (ngx_strncasecmp(arg
[0].data
, (u_char
*) "CRAM-MD5", 8) == 0) {
883 return NGX_MAIL_AUTH_CRAM_MD5
;
887 return NGX_MAIL_PARSE_INVALID_COMMAND
;