Groonga 3.0.9 Source Code Document
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
ngx_mail_parse.c
Go to the documentation of this file.
1 
2 /*
3  * Copyright (C) Igor Sysoev
4  * Copyright (C) Nginx, Inc.
5  */
6 
7 
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10 #include <ngx_event.h>
11 #include <ngx_mail.h>
12 #include <ngx_mail_pop3_module.h>
13 #include <ngx_mail_imap_module.h>
14 #include <ngx_mail_smtp_module.h>
15 
16 
19 {
20  u_char ch, *p, *c, c0, c1, c2, c3;
21  ngx_str_t *arg;
22  enum {
23  sw_start = 0,
24  sw_spaces_before_argument,
25  sw_argument,
26  sw_almost_done
27  } state;
28 
29  state = s->state;
30 
31  for (p = s->buffer->pos; p < s->buffer->last; p++) {
32  ch = *p;
33 
34  switch (state) {
35 
36  /* POP3 command */
37  case sw_start:
38  if (ch == ' ' || ch == CR || ch == LF) {
39  c = s->buffer->start;
40 
41  if (p - c == 4) {
42 
43  c0 = ngx_toupper(c[0]);
44  c1 = ngx_toupper(c[1]);
45  c2 = ngx_toupper(c[2]);
46  c3 = ngx_toupper(c[3]);
47 
48  if (c0 == 'U' && c1 == 'S' && c2 == 'E' && c3 == 'R')
49  {
51 
52  } else if (c0 == 'P' && c1 == 'A' && c2 == 'S' && c3 == 'S')
53  {
55 
56  } else if (c0 == 'A' && c1 == 'P' && c2 == 'O' && c3 == 'P')
57  {
59 
60  } else if (c0 == 'Q' && c1 == 'U' && c2 == 'I' && c3 == 'T')
61  {
63 
64  } else if (c0 == 'C' && c1 == 'A' && c2 == 'P' && c3 == 'A')
65  {
67 
68  } else if (c0 == 'A' && c1 == 'U' && c2 == 'T' && c3 == 'H')
69  {
71 
72  } else if (c0 == 'N' && c1 == 'O' && c2 == 'O' && c3 == 'P')
73  {
75 #if (NGX_MAIL_SSL)
76  } else if (c0 == 'S' && c1 == 'T' && c2 == 'L' && c3 == 'S')
77  {
79 #endif
80  } else {
81  goto invalid;
82  }
83 
84  } else {
85  goto invalid;
86  }
87 
88  switch (ch) {
89  case ' ':
90  state = sw_spaces_before_argument;
91  break;
92  case CR:
93  state = sw_almost_done;
94  break;
95  case LF:
96  goto done;
97  }
98  break;
99  }
100 
101  if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z')) {
102  goto invalid;
103  }
104 
105  break;
106 
107  case sw_spaces_before_argument:
108  switch (ch) {
109  case ' ':
110  break;
111  case CR:
112  state = sw_almost_done;
113  s->arg_end = p;
114  break;
115  case LF:
116  s->arg_end = p;
117  goto done;
118  default:
119  if (s->args.nelts <= 2) {
120  state = sw_argument;
121  s->arg_start = p;
122  break;
123  }
124  goto invalid;
125  }
126  break;
127 
128  case sw_argument:
129  switch (ch) {
130 
131  case ' ':
132 
133  /*
134  * the space should be considered as part of the at username
135  * or password, but not of argument in other commands
136  */
137 
138  if (s->command == NGX_POP3_USER
139  || s->command == NGX_POP3_PASS)
140  {
141  break;
142  }
143 
144  /* fall through */
145 
146  case CR:
147  case LF:
148  arg = ngx_array_push(&s->args);
149  if (arg == NULL) {
150  return NGX_ERROR;
151  }
152  arg->len = p - s->arg_start;
153  arg->data = s->arg_start;
154  s->arg_start = NULL;
155 
156  switch (ch) {
157  case ' ':
158  state = sw_spaces_before_argument;
159  break;
160  case CR:
161  state = sw_almost_done;
162  break;
163  case LF:
164  goto done;
165  }
166  break;
167 
168  default:
169  break;
170  }
171  break;
172 
173  case sw_almost_done:
174  switch (ch) {
175  case LF:
176  goto done;
177  default:
178  goto invalid;
179  }
180  }
181  }
182 
183  s->buffer->pos = p;
184  s->state = state;
185 
186  return NGX_AGAIN;
187 
188 done:
189 
190  s->buffer->pos = p + 1;
191 
192  if (s->arg_start) {
193  arg = ngx_array_push(&s->args);
194  if (arg == NULL) {
195  return NGX_ERROR;
196  }
197  arg->len = s->arg_end - s->arg_start;
198  arg->data = s->arg_start;
199  s->arg_start = NULL;
200  }
201 
202  s->state = (s->command != NGX_POP3_AUTH) ? sw_start : sw_argument;
203 
204  return NGX_OK;
205 
206 invalid:
207 
208  s->state = sw_start;
209  s->arg_start = NULL;
210 
212 }
213 
214 
215 ngx_int_t
217 {
218  u_char ch, *p, *c;
219  ngx_str_t *arg;
220  enum {
221  sw_start = 0,
222  sw_spaces_before_command,
223  sw_command,
224  sw_spaces_before_argument,
225  sw_argument,
226  sw_backslash,
227  sw_literal,
228  sw_no_sync_literal_argument,
229  sw_start_literal_argument,
230  sw_literal_argument,
231  sw_end_literal_argument,
232  sw_almost_done
233  } state;
234 
235  state = s->state;
236 
237  for (p = s->buffer->pos; p < s->buffer->last; p++) {
238  ch = *p;
239 
240  switch (state) {
241 
242  /* IMAP tag */
243  case sw_start:
244  switch (ch) {
245  case ' ':
246  s->tag.len = p - s->buffer->start + 1;
247  s->tag.data = s->buffer->start;
248  state = sw_spaces_before_command;
249  break;
250  case CR:
251  s->state = sw_start;
253  case LF:
254  s->state = sw_start;
256  }
257  break;
258 
259  case sw_spaces_before_command:
260  switch (ch) {
261  case ' ':
262  break;
263  case CR:
264  s->state = sw_start;
266  case LF:
267  s->state = sw_start;
269  default:
270  s->cmd_start = p;
271  state = sw_command;
272  break;
273  }
274  break;
275 
276  case sw_command:
277  if (ch == ' ' || ch == CR || ch == LF) {
278 
279  c = s->cmd_start;
280 
281  switch (p - c) {
282 
283  case 4:
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'))
288  {
289  s->command = NGX_IMAP_NOOP;
290 
291  } else {
292  goto invalid;
293  }
294  break;
295 
296  case 5:
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'))
302  {
303  s->command = NGX_IMAP_LOGIN;
304 
305  } else {
306  goto invalid;
307  }
308  break;
309 
310  case 6:
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'))
317  {
319 
320  } else {
321  goto invalid;
322  }
323  break;
324 
325 #if (NGX_MAIL_SSL)
326  case 8:
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'))
335  {
337 
338  } else {
339  goto invalid;
340  }
341  break;
342 #endif
343 
344  case 10:
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'))
355  {
357 
358  } else {
359  goto invalid;
360  }
361  break;
362 
363  case 12:
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'))
376  {
378 
379  } else {
380  goto invalid;
381  }
382  break;
383 
384  default:
385  goto invalid;
386  }
387 
388  switch (ch) {
389  case ' ':
390  state = sw_spaces_before_argument;
391  break;
392  case CR:
393  state = sw_almost_done;
394  break;
395  case LF:
396  goto done;
397  }
398  break;
399  }
400 
401  if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z')) {
402  goto invalid;
403  }
404 
405  break;
406 
407  case sw_spaces_before_argument:
408  switch (ch) {
409  case ' ':
410  break;
411  case CR:
412  state = sw_almost_done;
413  s->arg_end = p;
414  break;
415  case LF:
416  s->arg_end = p;
417  goto done;
418  case '"':
419  if (s->args.nelts <= 2) {
420  s->quoted = 1;
421  s->arg_start = p + 1;
422  state = sw_argument;
423  break;
424  }
425  goto invalid;
426  case '{':
427  if (s->args.nelts <= 2) {
428  state = sw_literal;
429  break;
430  }
431  goto invalid;
432  default:
433  if (s->args.nelts <= 2) {
434  s->arg_start = p;
435  state = sw_argument;
436  break;
437  }
438  goto invalid;
439  }
440  break;
441 
442  case sw_argument:
443  if (ch == ' ' && s->quoted) {
444  break;
445  }
446 
447  switch (ch) {
448  case '"':
449  if (!s->quoted) {
450  break;
451  }
452  s->quoted = 0;
453  /* fall through */
454  case ' ':
455  case CR:
456  case LF:
457  arg = ngx_array_push(&s->args);
458  if (arg == NULL) {
459  return NGX_ERROR;
460  }
461  arg->len = p - s->arg_start;
462  arg->data = s->arg_start;
463  s->arg_start = NULL;
464 
465  switch (ch) {
466  case '"':
467  case ' ':
468  state = sw_spaces_before_argument;
469  break;
470  case CR:
471  state = sw_almost_done;
472  break;
473  case LF:
474  goto done;
475  }
476  break;
477  case '\\':
478  if (s->quoted) {
479  s->backslash = 1;
480  state = sw_backslash;
481  }
482  break;
483  }
484  break;
485 
486  case sw_backslash:
487  switch (ch) {
488  case CR:
489  case LF:
490  goto invalid;
491  default:
492  state = sw_argument;
493  }
494  break;
495 
496  case sw_literal:
497  if (ch >= '0' && ch <= '9') {
498  s->literal_len = s->literal_len * 10 + (ch - '0');
499  break;
500  }
501  if (ch == '}') {
502  state = sw_start_literal_argument;
503  break;
504  }
505  if (ch == '+') {
506  state = sw_no_sync_literal_argument;
507  break;
508  }
509  goto invalid;
510 
511  case sw_no_sync_literal_argument:
512  if (ch == '}') {
513  s->no_sync_literal = 1;
514  state = sw_start_literal_argument;
515  break;
516  }
517  goto invalid;
518 
519  case sw_start_literal_argument:
520  switch (ch) {
521  case CR:
522  break;
523  case LF:
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;
529  }
530  state = sw_literal_argument;
531  s->no_sync_literal = 0;
532  break;
533  default:
534  goto invalid;
535  }
536  break;
537 
538  case sw_literal_argument:
539  if (s->literal_len && --s->literal_len) {
540  break;
541  }
542 
543  arg = ngx_array_push(&s->args);
544  if (arg == NULL) {
545  return NGX_ERROR;
546  }
547  arg->len = p + 1 - s->arg_start;
548  arg->data = s->arg_start;
549  s->arg_start = NULL;
550  state = sw_end_literal_argument;
551 
552  break;
553 
554  case sw_end_literal_argument:
555  switch (ch) {
556  case '{':
557  if (s->args.nelts <= 2) {
558  state = sw_literal;
559  break;
560  }
561  goto invalid;
562  case CR:
563  state = sw_almost_done;
564  break;
565  case LF:
566  goto done;
567  default:
568  state = sw_spaces_before_argument;
569  break;
570  }
571  break;
572 
573  case sw_almost_done:
574  switch (ch) {
575  case LF:
576  goto done;
577  default:
578  goto invalid;
579  }
580  }
581  }
582 
583  s->buffer->pos = p;
584  s->state = state;
585 
586  return NGX_AGAIN;
587 
588 done:
589 
590  s->buffer->pos = p + 1;
591 
592  if (s->arg_start) {
593  arg = ngx_array_push(&s->args);
594  if (arg == NULL) {
595  return NGX_ERROR;
596  }
597  arg->len = s->arg_end - s->arg_start;
598  arg->data = s->arg_start;
599 
600  s->arg_start = NULL;
601  s->cmd_start = NULL;
602  s->quoted = 0;
603  s->no_sync_literal = 0;
604  s->literal_len = 0;
605  }
606 
607  s->state = (s->command != NGX_IMAP_AUTHENTICATE) ? sw_start : sw_argument;
608 
609  return NGX_OK;
610 
611 invalid:
612 
613  s->state = sw_start;
614  s->quoted = 0;
615  s->no_sync_literal = 0;
616  s->literal_len = 0;
617 
619 }
620 
621 
622 ngx_int_t
624 {
625  u_char ch, *p, *c, c0, c1, c2, c3;
626  ngx_str_t *arg;
627  enum {
628  sw_start = 0,
629  sw_spaces_before_argument,
630  sw_argument,
631  sw_almost_done
632  } state;
633 
634  state = s->state;
635 
636  for (p = s->buffer->pos; p < s->buffer->last; p++) {
637  ch = *p;
638 
639  switch (state) {
640 
641  /* SMTP command */
642  case sw_start:
643  if (ch == ' ' || ch == CR || ch == LF) {
644  c = s->buffer->start;
645 
646  if (p - c == 4) {
647 
648  c0 = ngx_toupper(c[0]);
649  c1 = ngx_toupper(c[1]);
650  c2 = ngx_toupper(c[2]);
651  c3 = ngx_toupper(c[3]);
652 
653  if (c0 == 'H' && c1 == 'E' && c2 == 'L' && c3 == 'O')
654  {
655  s->command = NGX_SMTP_HELO;
656 
657  } else if (c0 == 'E' && c1 == 'H' && c2 == 'L' && c3 == 'O')
658  {
659  s->command = NGX_SMTP_EHLO;
660 
661  } else if (c0 == 'Q' && c1 == 'U' && c2 == 'I' && c3 == 'T')
662  {
663  s->command = NGX_SMTP_QUIT;
664 
665  } else if (c0 == 'A' && c1 == 'U' && c2 == 'T' && c3 == 'H')
666  {
667  s->command = NGX_SMTP_AUTH;
668 
669  } else if (c0 == 'N' && c1 == 'O' && c2 == 'O' && c3 == 'P')
670  {
671  s->command = NGX_SMTP_NOOP;
672 
673  } else if (c0 == 'M' && c1 == 'A' && c2 == 'I' && c3 == 'L')
674  {
675  s->command = NGX_SMTP_MAIL;
676 
677  } else if (c0 == 'R' && c1 == 'S' && c2 == 'E' && c3 == 'T')
678  {
679  s->command = NGX_SMTP_RSET;
680 
681  } else if (c0 == 'R' && c1 == 'C' && c2 == 'P' && c3 == 'T')
682  {
683  s->command = NGX_SMTP_RCPT;
684 
685  } else if (c0 == 'V' && c1 == 'R' && c2 == 'F' && c3 == 'Y')
686  {
687  s->command = NGX_SMTP_VRFY;
688 
689  } else if (c0 == 'E' && c1 == 'X' && c2 == 'P' && c3 == 'N')
690  {
691  s->command = NGX_SMTP_EXPN;
692 
693  } else if (c0 == 'H' && c1 == 'E' && c2 == 'L' && c3 == 'P')
694  {
695  s->command = NGX_SMTP_HELP;
696 
697  } else {
698  goto invalid;
699  }
700 #if (NGX_MAIL_SSL)
701  } else if (p - c == 8) {
702 
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'))
711  {
713 
714  } else {
715  goto invalid;
716  }
717 #endif
718  } else {
719  goto invalid;
720  }
721 
722  switch (ch) {
723  case ' ':
724  state = sw_spaces_before_argument;
725  break;
726  case CR:
727  state = sw_almost_done;
728  break;
729  case LF:
730  goto done;
731  }
732  break;
733  }
734 
735  if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z')) {
736  goto invalid;
737  }
738 
739  break;
740 
741  case sw_spaces_before_argument:
742  switch (ch) {
743  case ' ':
744  break;
745  case CR:
746  state = sw_almost_done;
747  s->arg_end = p;
748  break;
749  case LF:
750  s->arg_end = p;
751  goto done;
752  default:
753  if (s->args.nelts <= 10) {
754  state = sw_argument;
755  s->arg_start = p;
756  break;
757  }
758  goto invalid;
759  }
760  break;
761 
762  case sw_argument:
763  switch (ch) {
764  case ' ':
765  case CR:
766  case LF:
767  arg = ngx_array_push(&s->args);
768  if (arg == NULL) {
769  return NGX_ERROR;
770  }
771  arg->len = p - s->arg_start;
772  arg->data = s->arg_start;
773  s->arg_start = NULL;
774 
775  switch (ch) {
776  case ' ':
777  state = sw_spaces_before_argument;
778  break;
779  case CR:
780  state = sw_almost_done;
781  break;
782  case LF:
783  goto done;
784  }
785  break;
786 
787  default:
788  break;
789  }
790  break;
791 
792  case sw_almost_done:
793  switch (ch) {
794  case LF:
795  goto done;
796  default:
797  goto invalid;
798  }
799  }
800  }
801 
802  s->buffer->pos = p;
803  s->state = state;
804 
805  return NGX_AGAIN;
806 
807 done:
808 
809  s->buffer->pos = p + 1;
810 
811  if (s->arg_start) {
812  arg = ngx_array_push(&s->args);
813  if (arg == NULL) {
814  return NGX_ERROR;
815  }
816  arg->len = s->arg_end - s->arg_start;
817  arg->data = s->arg_start;
818  s->arg_start = NULL;
819  }
820 
821  s->state = (s->command != NGX_SMTP_AUTH) ? sw_start : sw_argument;
822 
823  return NGX_OK;
824 
825 invalid:
826 
827  s->state = sw_start;
828  s->arg_start = NULL;
829 
831 }
832 
833 
834 ngx_int_t
836 {
837  ngx_str_t *arg;
838 
839 #if (NGX_MAIL_SSL)
840  if (ngx_mail_starttls_only(s, c)) {
842  }
843 #endif
844 
845  arg = s->args.elts;
846 
847  if (arg[0].len == 5) {
848 
849  if (ngx_strncasecmp(arg[0].data, (u_char *) "LOGIN", 5) == 0) {
850 
851  if (s->args.nelts == 1) {
852  return NGX_MAIL_AUTH_LOGIN;
853  }
854 
855  if (s->args.nelts == 2) {
857  }
858 
860  }
861 
862  if (ngx_strncasecmp(arg[0].data, (u_char *) "PLAIN", 5) == 0) {
863 
864  if (s->args.nelts == 1) {
865  return NGX_MAIL_AUTH_PLAIN;
866  }
867 
868  if (s->args.nelts == 2) {
869  return ngx_mail_auth_plain(s, c, 1);
870  }
871  }
872 
874  }
875 
876  if (arg[0].len == 8) {
877 
878  if (s->args.nelts != 1) {
880  }
881 
882  if (ngx_strncasecmp(arg[0].data, (u_char *) "CRAM-MD5", 8) == 0) {
883  return NGX_MAIL_AUTH_CRAM_MD5;
884  }
885  }
886 
888 }