Mercurial > hg > nginx-mail
annotate src/mail/ngx_mail_parse.c @ 436:9b19e26b2660
Mail: smtp pipelining support.
Basically, this does the following two changes (and corresponding
modifications of related code):
1. Does not reset session buffer unless it's reached it's end, and always
wait for LF to terminate command (even if we detected invalid command).
2. Record command name as the first argument to make it available for
handlers (since now we can't assume that command starts from s->buffer->start).
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Thu, 11 Sep 2008 15:26:25 +0400 |
parents | 52b28d322d76 |
children | d67e93e97b4a |
rev | line source |
---|---|
290 | 1 |
2 /* | |
3 * Copyright (C) Igor Sysoev | |
4 */ | |
5 | |
6 | |
7 #include <ngx_config.h> | |
8 #include <ngx_core.h> | |
9 #include <ngx_event.h> | |
10 #include <ngx_mail.h> | |
11 | |
12 | |
336 | 13 ngx_int_t |
14 ngx_mail_pop3_parse_command(ngx_mail_session_t *s) | |
290 | 15 { |
16 u_char ch, *p, *c, c0, c1, c2, c3; | |
17 ngx_str_t *arg; | |
18 enum { | |
19 sw_start = 0, | |
20 sw_spaces_before_argument, | |
21 sw_argument, | |
22 sw_almost_done | |
23 } state; | |
24 | |
25 state = s->state; | |
26 | |
27 for (p = s->buffer->pos; p < s->buffer->last; p++) { | |
28 ch = *p; | |
29 | |
30 switch (state) { | |
31 | |
32 /* POP3 command */ | |
33 case sw_start: | |
34 if (ch == ' ' || ch == CR || ch == LF) { | |
35 c = s->buffer->start; | |
36 | |
37 if (p - c == 4) { | |
38 | |
39 c0 = ngx_toupper(c[0]); | |
40 c1 = ngx_toupper(c[1]); | |
41 c2 = ngx_toupper(c[2]); | |
42 c3 = ngx_toupper(c[3]); | |
43 | |
44 if (c0 == 'U' && c1 == 'S' && c2 == 'E' && c3 == 'R') | |
45 { | |
46 s->command = NGX_POP3_USER; | |
47 | |
48 } else if (c0 == 'P' && c1 == 'A' && c2 == 'S' && c3 == 'S') | |
49 { | |
50 s->command = NGX_POP3_PASS; | |
51 | |
52 } else if (c0 == 'A' && c1 == 'P' && c2 == 'O' && c3 == 'P') | |
53 { | |
54 s->command = NGX_POP3_APOP; | |
55 | |
56 } else if (c0 == 'Q' && c1 == 'U' && c2 == 'I' && c3 == 'T') | |
57 { | |
58 s->command = NGX_POP3_QUIT; | |
59 | |
60 } else if (c0 == 'C' && c1 == 'A' && c2 == 'P' && c3 == 'A') | |
61 { | |
62 s->command = NGX_POP3_CAPA; | |
63 | |
64 } else if (c0 == 'A' && c1 == 'U' && c2 == 'T' && c3 == 'H') | |
65 { | |
66 s->command = NGX_POP3_AUTH; | |
67 | |
68 } else if (c0 == 'N' && c1 == 'O' && c2 == 'O' && c3 == 'P') | |
69 { | |
70 s->command = NGX_POP3_NOOP; | |
71 #if (NGX_MAIL_SSL) | |
72 } else if (c0 == 'S' && c1 == 'T' && c2 == 'L' && c3 == 'S') | |
73 { | |
74 s->command = NGX_POP3_STLS; | |
75 #endif | |
76 } else { | |
77 goto invalid; | |
78 } | |
79 | |
80 } else { | |
81 goto invalid; | |
82 } | |
83 | |
84 switch (ch) { | |
85 case ' ': | |
86 state = sw_spaces_before_argument; | |
87 break; | |
88 case CR: | |
89 state = sw_almost_done; | |
90 break; | |
91 case LF: | |
92 goto done; | |
93 } | |
94 break; | |
95 } | |
96 | |
97 if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z')) { | |
98 goto invalid; | |
99 } | |
100 | |
101 break; | |
102 | |
103 case sw_spaces_before_argument: | |
104 switch (ch) { | |
105 case ' ': | |
106 break; | |
107 case CR: | |
108 state = sw_almost_done; | |
109 s->arg_end = p; | |
110 break; | |
111 case LF: | |
112 s->arg_end = p; | |
113 goto done; | |
114 default: | |
115 if (s->args.nelts <= 2) { | |
116 state = sw_argument; | |
117 s->arg_start = p; | |
118 break; | |
119 } | |
120 goto invalid; | |
121 } | |
122 break; | |
123 | |
124 case sw_argument: | |
125 switch (ch) { | |
126 | |
127 case ' ': | |
128 | |
129 /* | |
130 * the space should be considered as part of the at username | |
131 * or password, but not of argument in other commands | |
132 */ | |
133 | |
134 if (s->command == NGX_POP3_USER | |
135 || s->command == NGX_POP3_PASS) | |
136 { | |
137 break; | |
138 } | |
139 | |
140 /* fall through */ | |
141 | |
142 case CR: | |
143 case LF: | |
144 arg = ngx_array_push(&s->args); | |
145 if (arg == NULL) { | |
146 return NGX_ERROR; | |
147 } | |
148 arg->len = p - s->arg_start; | |
149 arg->data = s->arg_start; | |
150 s->arg_start = NULL; | |
151 | |
152 switch (ch) { | |
153 case ' ': | |
154 state = sw_spaces_before_argument; | |
155 break; | |
156 case CR: | |
157 state = sw_almost_done; | |
158 break; | |
159 case LF: | |
160 goto done; | |
161 } | |
162 break; | |
163 | |
164 default: | |
165 break; | |
166 } | |
167 break; | |
168 | |
169 case sw_almost_done: | |
170 switch (ch) { | |
171 case LF: | |
172 goto done; | |
173 default: | |
174 goto invalid; | |
175 } | |
176 } | |
177 } | |
178 | |
179 s->buffer->pos = p; | |
180 s->state = state; | |
181 | |
182 return NGX_AGAIN; | |
183 | |
184 done: | |
185 | |
186 s->buffer->pos = p + 1; | |
187 | |
188 if (s->arg_start) { | |
189 arg = ngx_array_push(&s->args); | |
190 if (arg == NULL) { | |
191 return NGX_ERROR; | |
192 } | |
193 arg->len = s->arg_end - s->arg_start; | |
194 arg->data = s->arg_start; | |
195 s->arg_start = NULL; | |
196 } | |
197 | |
198 s->state = (s->command != NGX_POP3_AUTH) ? sw_start : sw_argument; | |
199 | |
200 return NGX_OK; | |
201 | |
202 invalid: | |
203 | |
204 s->state = sw_start; | |
205 s->arg_start = NULL; | |
206 | |
207 return NGX_MAIL_PARSE_INVALID_COMMAND; | |
208 } | |
209 | |
210 | |
336 | 211 ngx_int_t |
212 ngx_mail_imap_parse_command(ngx_mail_session_t *s) | |
290 | 213 { |
214 u_char ch, *p, *c; | |
215 ngx_str_t *arg; | |
216 enum { | |
217 sw_start = 0, | |
218 sw_spaces_before_command, | |
219 sw_command, | |
220 sw_spaces_before_argument, | |
221 sw_argument, | |
222 sw_backslash, | |
223 sw_literal, | |
224 sw_no_sync_literal_argument, | |
225 sw_start_literal_argument, | |
226 sw_literal_argument, | |
227 sw_end_literal_argument, | |
228 sw_almost_done | |
229 } state; | |
230 | |
231 state = s->state; | |
232 | |
233 for (p = s->buffer->pos; p < s->buffer->last; p++) { | |
234 ch = *p; | |
235 | |
236 switch (state) { | |
237 | |
238 /* IMAP tag */ | |
239 case sw_start: | |
240 switch (ch) { | |
241 case ' ': | |
242 s->tag.len = p - s->buffer->start + 1; | |
243 s->tag.data = s->buffer->start; | |
244 state = sw_spaces_before_command; | |
245 break; | |
246 case CR: | |
247 s->state = sw_start; | |
248 return NGX_MAIL_PARSE_INVALID_COMMAND; | |
249 case LF: | |
250 s->state = sw_start; | |
251 return NGX_MAIL_PARSE_INVALID_COMMAND; | |
252 } | |
253 break; | |
254 | |
255 case sw_spaces_before_command: | |
256 switch (ch) { | |
257 case ' ': | |
258 break; | |
259 case CR: | |
260 s->state = sw_start; | |
261 return NGX_MAIL_PARSE_INVALID_COMMAND; | |
262 case LF: | |
263 s->state = sw_start; | |
264 return NGX_MAIL_PARSE_INVALID_COMMAND; | |
265 default: | |
266 s->cmd_start = p; | |
267 state = sw_command; | |
268 break; | |
269 } | |
270 break; | |
271 | |
272 case sw_command: | |
273 if (ch == ' ' || ch == CR || ch == LF) { | |
274 | |
275 c = s->cmd_start; | |
276 | |
277 switch (p - c) { | |
278 | |
279 case 4: | |
280 if ((c[0] == 'N' || c[0] == 'n') | |
281 && (c[1] == 'O'|| c[1] == 'o') | |
282 && (c[2] == 'O'|| c[2] == 'o') | |
283 && (c[3] == 'P'|| c[3] == 'p')) | |
284 { | |
285 s->command = NGX_IMAP_NOOP; | |
286 | |
287 } else { | |
288 goto invalid; | |
289 } | |
290 break; | |
291 | |
292 case 5: | |
293 if ((c[0] == 'L'|| c[0] == 'l') | |
294 && (c[1] == 'O'|| c[1] == 'o') | |
295 && (c[2] == 'G'|| c[2] == 'g') | |
296 && (c[3] == 'I'|| c[3] == 'i') | |
297 && (c[4] == 'N'|| c[4] == 'n')) | |
298 { | |
299 s->command = NGX_IMAP_LOGIN; | |
300 | |
301 } else { | |
302 goto invalid; | |
303 } | |
304 break; | |
305 | |
306 case 6: | |
307 if ((c[0] == 'L'|| c[0] == 'l') | |
308 && (c[1] == 'O'|| c[1] == 'o') | |
309 && (c[2] == 'G'|| c[2] == 'g') | |
310 && (c[3] == 'O'|| c[3] == 'o') | |
311 && (c[4] == 'U'|| c[4] == 'u') | |
312 && (c[5] == 'T'|| c[5] == 't')) | |
313 { | |
314 s->command = NGX_IMAP_LOGOUT; | |
315 | |
316 } else { | |
317 goto invalid; | |
318 } | |
319 break; | |
320 | |
321 #if (NGX_MAIL_SSL) | |
322 case 8: | |
323 if ((c[0] == 'S'|| c[0] == 's') | |
324 && (c[1] == 'T'|| c[1] == 't') | |
325 && (c[2] == 'A'|| c[2] == 'a') | |
326 && (c[3] == 'R'|| c[3] == 'r') | |
327 && (c[4] == 'T'|| c[4] == 't') | |
328 && (c[5] == 'T'|| c[5] == 't') | |
329 && (c[6] == 'L'|| c[6] == 'l') | |
330 && (c[7] == 'S'|| c[7] == 's')) | |
331 { | |
332 s->command = NGX_IMAP_STARTTLS; | |
333 | |
334 } else { | |
335 goto invalid; | |
336 } | |
337 break; | |
338 #endif | |
339 | |
340 case 10: | |
341 if ((c[0] == 'C'|| c[0] == 'c') | |
342 && (c[1] == 'A'|| c[1] == 'a') | |
343 && (c[2] == 'P'|| c[2] == 'p') | |
344 && (c[3] == 'A'|| c[3] == 'a') | |
345 && (c[4] == 'B'|| c[4] == 'b') | |
346 && (c[5] == 'I'|| c[5] == 'i') | |
347 && (c[6] == 'L'|| c[6] == 'l') | |
348 && (c[7] == 'I'|| c[7] == 'i') | |
349 && (c[8] == 'T'|| c[8] == 't') | |
350 && (c[9] == 'Y'|| c[9] == 'y')) | |
351 { | |
352 s->command = NGX_IMAP_CAPABILITY; | |
353 | |
354 } else { | |
355 goto invalid; | |
356 } | |
357 break; | |
358 | |
322 | 359 case 12: |
360 if ((c[0] == 'A'|| c[0] == 'a') | |
361 && (c[1] == 'U'|| c[1] == 'u') | |
362 && (c[2] == 'T'|| c[2] == 't') | |
363 && (c[3] == 'H'|| c[3] == 'h') | |
364 && (c[4] == 'E'|| c[4] == 'e') | |
365 && (c[5] == 'N'|| c[5] == 'n') | |
366 && (c[6] == 'T'|| c[6] == 't') | |
367 && (c[7] == 'I'|| c[7] == 'i') | |
368 && (c[8] == 'C'|| c[8] == 'c') | |
369 && (c[9] == 'A'|| c[9] == 'a') | |
370 && (c[10] == 'T'|| c[10] == 't') | |
371 && (c[11] == 'E'|| c[11] == 'e')) | |
372 { | |
373 s->command = NGX_IMAP_AUTHENTICATE; | |
374 | |
375 } else { | |
376 goto invalid; | |
377 } | |
378 break; | |
379 | |
290 | 380 default: |
381 goto invalid; | |
382 } | |
383 | |
384 switch (ch) { | |
385 case ' ': | |
386 state = sw_spaces_before_argument; | |
387 break; | |
388 case CR: | |
389 state = sw_almost_done; | |
390 break; | |
391 case LF: | |
392 goto done; | |
393 } | |
394 break; | |
395 } | |
396 | |
397 if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z')) { | |
398 goto invalid; | |
399 } | |
400 | |
401 break; | |
402 | |
403 case sw_spaces_before_argument: | |
404 switch (ch) { | |
405 case ' ': | |
406 break; | |
407 case CR: | |
408 state = sw_almost_done; | |
409 s->arg_end = p; | |
410 break; | |
411 case LF: | |
412 s->arg_end = p; | |
413 goto done; | |
414 case '"': | |
415 if (s->args.nelts <= 2) { | |
416 s->quoted = 1; | |
417 s->arg_start = p + 1; | |
418 state = sw_argument; | |
419 break; | |
420 } | |
421 goto invalid; | |
422 case '{': | |
423 if (s->args.nelts <= 2) { | |
424 state = sw_literal; | |
425 break; | |
426 } | |
427 goto invalid; | |
428 default: | |
429 if (s->args.nelts <= 2) { | |
430 s->arg_start = p; | |
431 state = sw_argument; | |
432 break; | |
433 } | |
434 goto invalid; | |
435 } | |
436 break; | |
437 | |
438 case sw_argument: | |
328 | 439 if (ch == ' ' && s->quoted) { |
440 break; | |
441 } | |
442 | |
290 | 443 switch (ch) { |
444 case '"': | |
445 if (!s->quoted) { | |
446 break; | |
447 } | |
448 s->quoted = 0; | |
449 /* fall through */ | |
450 case ' ': | |
451 case CR: | |
452 case LF: | |
453 arg = ngx_array_push(&s->args); | |
454 if (arg == NULL) { | |
455 return NGX_ERROR; | |
456 } | |
457 arg->len = p - s->arg_start; | |
458 arg->data = s->arg_start; | |
459 s->arg_start = NULL; | |
460 | |
461 switch (ch) { | |
462 case '"': | |
463 case ' ': | |
464 state = sw_spaces_before_argument; | |
465 break; | |
466 case CR: | |
467 state = sw_almost_done; | |
468 break; | |
469 case LF: | |
470 goto done; | |
471 } | |
472 break; | |
473 case '\\': | |
474 if (s->quoted) { | |
475 s->backslash = 1; | |
476 state = sw_backslash; | |
477 } | |
478 break; | |
479 } | |
480 break; | |
481 | |
482 case sw_backslash: | |
483 switch (ch) { | |
484 case CR: | |
485 case LF: | |
486 goto invalid; | |
487 default: | |
488 state = sw_argument; | |
489 } | |
490 break; | |
491 | |
492 case sw_literal: | |
493 if (ch >= '0' && ch <= '9') { | |
494 s->literal_len = s->literal_len * 10 + (ch - '0'); | |
495 break; | |
496 } | |
497 if (ch == '}') { | |
498 state = sw_start_literal_argument; | |
499 break; | |
500 } | |
501 if (ch == '+') { | |
502 state = sw_no_sync_literal_argument; | |
503 break; | |
504 } | |
505 goto invalid; | |
506 | |
507 case sw_no_sync_literal_argument: | |
508 if (ch == '}') { | |
509 s->no_sync_literal = 1; | |
510 state = sw_start_literal_argument; | |
511 break; | |
512 } | |
513 goto invalid; | |
514 | |
515 case sw_start_literal_argument: | |
516 switch (ch) { | |
517 case CR: | |
518 break; | |
519 case LF: | |
520 s->buffer->pos = p + 1; | |
521 s->arg_start = p + 1; | |
522 if (s->no_sync_literal == 0) { | |
523 s->state = sw_literal_argument; | |
524 return NGX_IMAP_NEXT; | |
525 } | |
526 state = sw_literal_argument; | |
527 s->no_sync_literal = 0; | |
528 break; | |
529 default: | |
530 goto invalid; | |
531 } | |
532 break; | |
533 | |
534 case sw_literal_argument: | |
535 if (s->literal_len && --s->literal_len) { | |
536 break; | |
537 } | |
538 | |
539 arg = ngx_array_push(&s->args); | |
540 if (arg == NULL) { | |
541 return NGX_ERROR; | |
542 } | |
543 arg->len = p + 1 - s->arg_start; | |
544 arg->data = s->arg_start; | |
545 s->arg_start = NULL; | |
546 state = sw_end_literal_argument; | |
547 | |
548 break; | |
549 | |
550 case sw_end_literal_argument: | |
551 switch (ch) { | |
552 case '{': | |
553 if (s->args.nelts <= 2) { | |
554 state = sw_literal; | |
555 break; | |
556 } | |
557 goto invalid; | |
558 case CR: | |
559 state = sw_almost_done; | |
560 break; | |
561 case LF: | |
562 goto done; | |
563 default: | |
564 state = sw_spaces_before_argument; | |
565 break; | |
566 } | |
567 break; | |
568 | |
569 case sw_almost_done: | |
570 switch (ch) { | |
571 case LF: | |
572 goto done; | |
573 default: | |
574 goto invalid; | |
575 } | |
576 } | |
577 } | |
578 | |
579 s->buffer->pos = p; | |
580 s->state = state; | |
581 | |
582 return NGX_AGAIN; | |
583 | |
584 done: | |
585 | |
586 s->buffer->pos = p + 1; | |
587 | |
588 if (s->arg_start) { | |
589 arg = ngx_array_push(&s->args); | |
590 if (arg == NULL) { | |
591 return NGX_ERROR; | |
592 } | |
593 arg->len = s->arg_end - s->arg_start; | |
594 arg->data = s->arg_start; | |
595 | |
596 s->arg_start = NULL; | |
597 s->cmd_start = NULL; | |
598 s->quoted = 0; | |
599 s->no_sync_literal = 0; | |
600 s->literal_len = 0; | |
601 } | |
602 | |
322 | 603 s->state = (s->command != NGX_IMAP_AUTHENTICATE) ? sw_start : sw_argument; |
290 | 604 |
605 return NGX_OK; | |
606 | |
607 invalid: | |
608 | |
609 s->state = sw_start; | |
610 s->quoted = 0; | |
611 s->no_sync_literal = 0; | |
612 s->literal_len = 0; | |
613 | |
614 return NGX_MAIL_PARSE_INVALID_COMMAND; | |
615 } | |
616 | |
617 | |
336 | 618 ngx_int_t |
619 ngx_mail_smtp_parse_command(ngx_mail_session_t *s) | |
290 | 620 { |
621 u_char ch, *p, *c, c0, c1, c2, c3; | |
622 ngx_str_t *arg; | |
623 enum { | |
624 sw_start = 0, | |
436
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
409
diff
changeset
|
625 sw_command, |
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
409
diff
changeset
|
626 sw_invalid, |
290 | 627 sw_spaces_before_argument, |
628 sw_argument, | |
629 sw_almost_done | |
630 } state; | |
631 | |
632 state = s->state; | |
633 | |
634 for (p = s->buffer->pos; p < s->buffer->last; p++) { | |
635 ch = *p; | |
636 | |
637 switch (state) { | |
638 | |
639 /* SMTP command */ | |
640 case sw_start: | |
436
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
409
diff
changeset
|
641 s->arg_start = p; |
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
409
diff
changeset
|
642 state = sw_command; |
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
409
diff
changeset
|
643 |
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
409
diff
changeset
|
644 /* fall through */ |
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
409
diff
changeset
|
645 |
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
409
diff
changeset
|
646 case sw_command: |
290 | 647 if (ch == ' ' || ch == CR || ch == LF) { |
436
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
409
diff
changeset
|
648 c = s->arg_start; |
290 | 649 |
650 if (p - c == 4) { | |
651 | |
652 c0 = ngx_toupper(c[0]); | |
653 c1 = ngx_toupper(c[1]); | |
654 c2 = ngx_toupper(c[2]); | |
655 c3 = ngx_toupper(c[3]); | |
656 | |
657 if (c0 == 'H' && c1 == 'E' && c2 == 'L' && c3 == 'O') | |
658 { | |
659 s->command = NGX_SMTP_HELO; | |
660 | |
661 } else if (c0 == 'E' && c1 == 'H' && c2 == 'L' && c3 == 'O') | |
662 { | |
663 s->command = NGX_SMTP_EHLO; | |
664 | |
665 } else if (c0 == 'Q' && c1 == 'U' && c2 == 'I' && c3 == 'T') | |
666 { | |
667 s->command = NGX_SMTP_QUIT; | |
668 | |
669 } else if (c0 == 'A' && c1 == 'U' && c2 == 'T' && c3 == 'H') | |
670 { | |
671 s->command = NGX_SMTP_AUTH; | |
672 | |
673 } else if (c0 == 'N' && c1 == 'O' && c2 == 'O' && c3 == 'P') | |
674 { | |
675 s->command = NGX_SMTP_NOOP; | |
676 | |
677 } else if (c0 == 'M' && c1 == 'A' && c2 == 'I' && c3 == 'L') | |
678 { | |
679 s->command = NGX_SMTP_MAIL; | |
680 | |
681 } else if (c0 == 'R' && c1 == 'S' && c2 == 'E' && c3 == 'T') | |
682 { | |
683 s->command = NGX_SMTP_RSET; | |
684 | |
322 | 685 } else if (c0 == 'R' && c1 == 'C' && c2 == 'P' && c3 == 'T') |
686 { | |
687 s->command = NGX_SMTP_RCPT; | |
688 | |
689 } else if (c0 == 'V' && c1 == 'R' && c2 == 'F' && c3 == 'Y') | |
690 { | |
691 s->command = NGX_SMTP_VRFY; | |
692 | |
693 } else if (c0 == 'E' && c1 == 'X' && c2 == 'P' && c3 == 'N') | |
694 { | |
695 s->command = NGX_SMTP_EXPN; | |
696 | |
697 } else if (c0 == 'H' && c1 == 'E' && c2 == 'L' && c3 == 'P') | |
698 { | |
699 s->command = NGX_SMTP_HELP; | |
700 | |
290 | 701 } else { |
702 goto invalid; | |
703 } | |
322 | 704 #if (NGX_MAIL_SSL) |
705 } else if (p - c == 8) { | |
290 | 706 |
322 | 707 if ((c[0] == 'S'|| c[0] == 's') |
708 && (c[1] == 'T'|| c[1] == 't') | |
709 && (c[2] == 'A'|| c[2] == 'a') | |
710 && (c[3] == 'R'|| c[3] == 'r') | |
711 && (c[4] == 'T'|| c[4] == 't') | |
712 && (c[5] == 'T'|| c[5] == 't') | |
713 && (c[6] == 'L'|| c[6] == 'l') | |
714 && (c[7] == 'S'|| c[7] == 's')) | |
715 { | |
716 s->command = NGX_SMTP_STARTTLS; | |
717 | |
718 } else { | |
719 goto invalid; | |
720 } | |
721 #endif | |
290 | 722 } else { |
723 goto invalid; | |
724 } | |
725 | |
436
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
409
diff
changeset
|
726 arg = ngx_array_push(&s->args); |
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
409
diff
changeset
|
727 if (arg == NULL) { |
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
409
diff
changeset
|
728 return NGX_ERROR; |
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
409
diff
changeset
|
729 } |
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
409
diff
changeset
|
730 arg->len = p - s->arg_start; |
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
409
diff
changeset
|
731 arg->data = s->arg_start; |
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
409
diff
changeset
|
732 s->arg_start = NULL; |
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
409
diff
changeset
|
733 |
290 | 734 switch (ch) { |
735 case ' ': | |
736 state = sw_spaces_before_argument; | |
737 break; | |
738 case CR: | |
739 state = sw_almost_done; | |
740 break; | |
741 case LF: | |
742 goto done; | |
743 } | |
744 break; | |
745 } | |
746 | |
747 if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z')) { | |
748 goto invalid; | |
749 } | |
750 | |
751 break; | |
752 | |
436
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
409
diff
changeset
|
753 case sw_invalid: |
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
409
diff
changeset
|
754 goto invalid; |
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
409
diff
changeset
|
755 |
290 | 756 case sw_spaces_before_argument: |
757 switch (ch) { | |
758 case ' ': | |
759 break; | |
760 case CR: | |
761 state = sw_almost_done; | |
762 s->arg_end = p; | |
763 break; | |
764 case LF: | |
765 s->arg_end = p; | |
766 goto done; | |
767 default: | |
401
98c752b41cbc
Mail: raise number of arguments parsed in smtp.
Maxim Dounin <mdounin@mdounin.ru>
parents:
398
diff
changeset
|
768 if (s->args.nelts <= 10) { |
290 | 769 state = sw_argument; |
770 s->arg_start = p; | |
771 break; | |
772 } | |
773 goto invalid; | |
774 } | |
775 break; | |
776 | |
777 case sw_argument: | |
778 switch (ch) { | |
779 case ' ': | |
780 case CR: | |
781 case LF: | |
782 arg = ngx_array_push(&s->args); | |
783 if (arg == NULL) { | |
784 return NGX_ERROR; | |
785 } | |
786 arg->len = p - s->arg_start; | |
787 arg->data = s->arg_start; | |
788 s->arg_start = NULL; | |
789 | |
790 switch (ch) { | |
791 case ' ': | |
792 state = sw_spaces_before_argument; | |
793 break; | |
794 case CR: | |
795 state = sw_almost_done; | |
796 break; | |
797 case LF: | |
798 goto done; | |
799 } | |
800 break; | |
801 | |
802 default: | |
803 break; | |
804 } | |
805 break; | |
806 | |
807 case sw_almost_done: | |
808 switch (ch) { | |
809 case LF: | |
810 goto done; | |
811 default: | |
812 goto invalid; | |
813 } | |
814 } | |
815 } | |
816 | |
817 s->buffer->pos = p; | |
818 s->state = state; | |
819 | |
820 return NGX_AGAIN; | |
821 | |
822 done: | |
823 | |
824 s->buffer->pos = p + 1; | |
825 | |
826 if (s->arg_start) { | |
827 arg = ngx_array_push(&s->args); | |
828 if (arg == NULL) { | |
829 return NGX_ERROR; | |
830 } | |
831 arg->len = s->arg_end - s->arg_start; | |
832 arg->data = s->arg_start; | |
833 s->arg_start = NULL; | |
834 } | |
835 | |
836 s->state = (s->command != NGX_SMTP_AUTH) ? sw_start : sw_argument; | |
837 | |
838 return NGX_OK; | |
839 | |
840 invalid: | |
841 | |
436
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
409
diff
changeset
|
842 s->state = sw_invalid; |
290 | 843 s->arg_start = NULL; |
844 | |
436
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
409
diff
changeset
|
845 /* skip invalid command till LF */ |
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
409
diff
changeset
|
846 |
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
409
diff
changeset
|
847 for (p = s->buffer->pos; p < s->buffer->last; p++) { |
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
409
diff
changeset
|
848 if (*p == LF) { |
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
409
diff
changeset
|
849 s->state = sw_start; |
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
409
diff
changeset
|
850 p++; |
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
409
diff
changeset
|
851 break; |
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
409
diff
changeset
|
852 } |
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
409
diff
changeset
|
853 } |
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
409
diff
changeset
|
854 |
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
409
diff
changeset
|
855 s->buffer->pos = p; |
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
409
diff
changeset
|
856 |
290 | 857 return NGX_MAIL_PARSE_INVALID_COMMAND; |
858 } | |
336 | 859 |
860 | |
861 ngx_int_t | |
862 ngx_mail_auth_parse(ngx_mail_session_t *s, ngx_connection_t *c) | |
863 { | |
864 ngx_str_t *arg; | |
436
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
409
diff
changeset
|
865 ngx_uint_t nelts; |
336 | 866 |
867 #if (NGX_MAIL_SSL) | |
868 if (ngx_mail_starttls_only(s, c)) { | |
869 return NGX_MAIL_PARSE_INVALID_COMMAND; | |
870 } | |
871 #endif | |
872 | |
873 arg = s->args.elts; | |
436
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
409
diff
changeset
|
874 nelts = s->args.nelts; |
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
409
diff
changeset
|
875 |
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
409
diff
changeset
|
876 if (s->protocol == NGX_MAIL_SMTP_PROTOCOL) { |
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
409
diff
changeset
|
877 arg++; |
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
409
diff
changeset
|
878 nelts--; |
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
409
diff
changeset
|
879 } |
336 | 880 |
881 if (arg[0].len == 5) { | |
882 | |
883 if (ngx_strncasecmp(arg[0].data, (u_char *) "LOGIN", 5) == 0) { | |
884 | |
436
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
409
diff
changeset
|
885 if (nelts == 1) { |
336 | 886 return NGX_MAIL_AUTH_LOGIN; |
887 } | |
888 | |
889 return NGX_MAIL_PARSE_INVALID_COMMAND; | |
890 } | |
891 | |
892 if (ngx_strncasecmp(arg[0].data, (u_char *) "PLAIN", 5) == 0) { | |
893 | |
436
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
409
diff
changeset
|
894 if (nelts == 1) { |
336 | 895 return NGX_MAIL_AUTH_PLAIN; |
896 } | |
897 | |
436
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
409
diff
changeset
|
898 if (nelts == 2) { |
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
409
diff
changeset
|
899 return ngx_mail_auth_plain(s, c, |
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
409
diff
changeset
|
900 (s->protocol == NGX_MAIL_SMTP_PROTOCOL) ? 2 : 1); |
336 | 901 } |
902 } | |
903 | |
904 return NGX_MAIL_PARSE_INVALID_COMMAND; | |
905 } | |
906 | |
907 if (arg[0].len == 8) { | |
908 | |
436
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
409
diff
changeset
|
909 if (nelts != 1) { |
336 | 910 return NGX_MAIL_PARSE_INVALID_COMMAND; |
911 } | |
912 | |
913 if (ngx_strncasecmp(arg[0].data, (u_char *) "CRAM-MD5", 8) == 0) { | |
914 return NGX_MAIL_AUTH_CRAM_MD5; | |
915 } | |
916 } | |
917 | |
918 return NGX_MAIL_PARSE_INVALID_COMMAND; | |
919 } |