Mercurial > hg > nginx-quic
annotate src/mail/ngx_mail_parse.c @ 4915:e62219793beb
Upstream: better detection of connect() failures with kqueue.
Pending EOF might be reported on both read and write events, whichever
comes first, so check both of them.
Patch by Yichun Zhang (agentzh), slightly modified.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Fri, 16 Nov 2012 18:29:19 +0000 |
parents | 4c36e15651f7 |
children | b6562f98bfd8 |
rev | line source |
---|---|
441
da8c5707af39
nginx-0.1.0-2004-09-28-12:34:51 import; set copyright and remove unused files
Igor Sysoev <igor@sysoev.ru>
parents:
422
diff
changeset
|
1 |
da8c5707af39
nginx-0.1.0-2004-09-28-12:34:51 import; set copyright and remove unused files
Igor Sysoev <igor@sysoev.ru>
parents:
422
diff
changeset
|
2 /* |
444
42d11f017717
nginx-0.1.0-2004-09-29-20:00:49 import; remove years from copyright
Igor Sysoev <igor@sysoev.ru>
parents:
441
diff
changeset
|
3 * Copyright (C) Igor Sysoev |
4412 | 4 * Copyright (C) Nginx, Inc. |
441
da8c5707af39
nginx-0.1.0-2004-09-28-12:34:51 import; set copyright and remove unused files
Igor Sysoev <igor@sysoev.ru>
parents:
422
diff
changeset
|
5 */ |
da8c5707af39
nginx-0.1.0-2004-09-28-12:34:51 import; set copyright and remove unused files
Igor Sysoev <igor@sysoev.ru>
parents:
422
diff
changeset
|
6 |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
7 |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
8 #include <ngx_config.h> |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
9 #include <ngx_core.h> |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
10 #include <ngx_event.h> |
1136 | 11 #include <ngx_mail.h> |
4759
4c36e15651f7
Fixed compilation with -Wmissing-prototypes.
Ruslan Ermilov <ru@nginx.com>
parents:
4412
diff
changeset
|
12 #include <ngx_mail_pop3_module.h> |
4c36e15651f7
Fixed compilation with -Wmissing-prototypes.
Ruslan Ermilov <ru@nginx.com>
parents:
4412
diff
changeset
|
13 #include <ngx_mail_imap_module.h> |
4c36e15651f7
Fixed compilation with -Wmissing-prototypes.
Ruslan Ermilov <ru@nginx.com>
parents:
4412
diff
changeset
|
14 #include <ngx_mail_smtp_module.h> |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
15 |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
16 |
1477 | 17 ngx_int_t |
18 ngx_mail_pop3_parse_command(ngx_mail_session_t *s) | |
1136 | 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 { | |
50 s->command = NGX_POP3_USER; | |
51 | |
52 } else if (c0 == 'P' && c1 == 'A' && c2 == 'S' && c3 == 'S') | |
53 { | |
54 s->command = NGX_POP3_PASS; | |
55 | |
56 } else if (c0 == 'A' && c1 == 'P' && c2 == 'O' && c3 == 'P') | |
57 { | |
58 s->command = NGX_POP3_APOP; | |
59 | |
60 } else if (c0 == 'Q' && c1 == 'U' && c2 == 'I' && c3 == 'T') | |
61 { | |
62 s->command = NGX_POP3_QUIT; | |
63 | |
64 } else if (c0 == 'C' && c1 == 'A' && c2 == 'P' && c3 == 'A') | |
65 { | |
66 s->command = NGX_POP3_CAPA; | |
67 | |
68 } else if (c0 == 'A' && c1 == 'U' && c2 == 'T' && c3 == 'H') | |
69 { | |
70 s->command = NGX_POP3_AUTH; | |
71 | |
72 } else if (c0 == 'N' && c1 == 'O' && c2 == 'O' && c3 == 'P') | |
73 { | |
74 s->command = NGX_POP3_NOOP; | |
75 #if (NGX_MAIL_SSL) | |
76 } else if (c0 == 'S' && c1 == 'T' && c2 == 'L' && c3 == 'S') | |
77 { | |
78 s->command = NGX_POP3_STLS; | |
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 | |
211 return NGX_MAIL_PARSE_INVALID_COMMAND; | |
212 } | |
213 | |
214 | |
1477 | 215 ngx_int_t |
216 ngx_mail_imap_parse_command(ngx_mail_session_t *s) | |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
217 { |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
218 u_char ch, *p, *c; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
219 ngx_str_t *arg; |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
220 enum { |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
221 sw_start = 0, |
527 | 222 sw_spaces_before_command, |
223 sw_command, | |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
224 sw_spaces_before_argument, |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
225 sw_argument, |
543 | 226 sw_backslash, |
527 | 227 sw_literal, |
543 | 228 sw_no_sync_literal_argument, |
527 | 229 sw_start_literal_argument, |
230 sw_literal_argument, | |
231 sw_end_literal_argument, | |
232 sw_almost_done | |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
233 } state; |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
234 |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
235 state = s->state; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
236 |
527 | 237 for (p = s->buffer->pos; p < s->buffer->last; p++) { |
238 ch = *p; | |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
239 |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
240 switch (state) { |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
241 |
527 | 242 /* IMAP tag */ |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
243 case sw_start: |
527 | 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; | |
1136 | 252 return NGX_MAIL_PARSE_INVALID_COMMAND; |
527 | 253 case LF: |
254 s->state = sw_start; | |
1136 | 255 return NGX_MAIL_PARSE_INVALID_COMMAND; |
527 | 256 } |
257 break; | |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
258 |
527 | 259 case sw_spaces_before_command: |
260 switch (ch) { | |
261 case ' ': | |
262 break; | |
263 case CR: | |
264 s->state = sw_start; | |
1136 | 265 return NGX_MAIL_PARSE_INVALID_COMMAND; |
527 | 266 case LF: |
267 s->state = sw_start; | |
1136 | 268 return NGX_MAIL_PARSE_INVALID_COMMAND; |
527 | 269 default: |
270 s->cmd_start = p; | |
271 state = sw_command; | |
272 break; | |
273 } | |
274 break; | |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
275 |
527 | 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')) | |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
288 { |
527 | 289 s->command = NGX_IMAP_NOOP; |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
290 |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
291 } else { |
527 | 292 goto invalid; |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
293 } |
527 | 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; | |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
309 |
527 | 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 { | |
318 s->command = NGX_IMAP_LOGOUT; | |
319 | |
320 } else { | |
321 goto invalid; | |
322 } | |
323 break; | |
324 | |
1136 | 325 #if (NGX_MAIL_SSL) |
583 | 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 { | |
336 s->command = NGX_IMAP_STARTTLS; | |
337 | |
338 } else { | |
339 goto invalid; | |
340 } | |
341 break; | |
342 #endif | |
343 | |
527 | 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 { | |
356 s->command = NGX_IMAP_CAPABILITY; | |
357 | |
358 } else { | |
359 goto invalid; | |
360 } | |
361 break; | |
362 | |
1323 | 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 { | |
377 s->command = NGX_IMAP_AUTHENTICATE; | |
378 | |
379 } else { | |
380 goto invalid; | |
381 } | |
382 break; | |
383 | |
527 | 384 default: |
385 goto invalid; | |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
386 } |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
387 |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
388 switch (ch) { |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
389 case ' ': |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
390 state = sw_spaces_before_argument; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
391 break; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
392 case CR: |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
393 state = sw_almost_done; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
394 break; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
395 case LF: |
527 | 396 goto done; |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
397 } |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
398 break; |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
399 } |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
400 |
527 | 401 if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z')) { |
402 goto invalid; | |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
403 } |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
404 |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
405 break; |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
406 |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
407 case sw_spaces_before_argument: |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
408 switch (ch) { |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
409 case ' ': |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
410 break; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
411 case CR: |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
412 state = sw_almost_done; |
527 | 413 s->arg_end = p; |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
414 break; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
415 case LF: |
527 | 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; | |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
432 default: |
527 | 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: | |
1405
fdd064faf26a
escape " ", "%", and %00-%1F in login and password
Igor Sysoev <igor@sysoev.ru>
parents:
1323
diff
changeset
|
443 if (ch == ' ' && s->quoted) { |
fdd064faf26a
escape " ", "%", and %00-%1F in login and password
Igor Sysoev <igor@sysoev.ru>
parents:
1323
diff
changeset
|
444 break; |
fdd064faf26a
escape " ", "%", and %00-%1F in login and password
Igor Sysoev <igor@sysoev.ru>
parents:
1323
diff
changeset
|
445 } |
fdd064faf26a
escape " ", "%", and %00-%1F in login and password
Igor Sysoev <igor@sysoev.ru>
parents:
1323
diff
changeset
|
446 |
527 | 447 switch (ch) { |
448 case '"': | |
449 if (!s->quoted) { | |
450 break; | |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
451 } |
527 | 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; | |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
464 |
527 | 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 } | |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
476 break; |
543 | 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; | |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
493 } |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
494 break; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
495 |
527 | 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 } | |
543 | 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 } | |
527 | 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; | |
543 | 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; | |
527 | 535 } |
543 | 536 break; |
527 | 537 |
538 case sw_literal_argument: | |
529 | 539 if (s->literal_len && --s->literal_len) { |
527 | 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: | |
529 | 568 state = sw_spaces_before_argument; |
569 break; | |
527 | 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; | |
543 | 599 |
527 | 600 s->arg_start = NULL; |
601 s->cmd_start = NULL; | |
602 s->quoted = 0; | |
543 | 603 s->no_sync_literal = 0; |
527 | 604 s->literal_len = 0; |
605 } | |
606 | |
1323 | 607 s->state = (s->command != NGX_IMAP_AUTHENTICATE) ? sw_start : sw_argument; |
527 | 608 |
609 return NGX_OK; | |
610 | |
611 invalid: | |
612 | |
613 s->state = sw_start; | |
614 s->quoted = 0; | |
543 | 615 s->no_sync_literal = 0; |
527 | 616 s->literal_len = 0; |
617 | |
1136 | 618 return NGX_MAIL_PARSE_INVALID_COMMAND; |
527 | 619 } |
620 | |
621 | |
1477 | 622 ngx_int_t |
623 ngx_mail_smtp_parse_command(ngx_mail_session_t *s) | |
527 | 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 | |
1136 | 641 /* SMTP command */ |
527 | 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 | |
1136 | 653 if (c0 == 'H' && c1 == 'E' && c2 == 'L' && c3 == 'O') |
527 | 654 { |
1136 | 655 s->command = NGX_SMTP_HELO; |
527 | 656 |
1136 | 657 } else if (c0 == 'E' && c1 == 'H' && c2 == 'L' && c3 == 'O') |
800 | 658 { |
1136 | 659 s->command = NGX_SMTP_EHLO; |
800 | 660 |
527 | 661 } else if (c0 == 'Q' && c1 == 'U' && c2 == 'I' && c3 == 'T') |
662 { | |
1136 | 663 s->command = NGX_SMTP_QUIT; |
527 | 664 |
809 | 665 } else if (c0 == 'A' && c1 == 'U' && c2 == 'T' && c3 == 'H') |
666 { | |
1136 | 667 s->command = NGX_SMTP_AUTH; |
809 | 668 |
527 | 669 } else if (c0 == 'N' && c1 == 'O' && c2 == 'O' && c3 == 'P') |
670 { | |
1136 | 671 s->command = NGX_SMTP_NOOP; |
672 | |
673 } else if (c0 == 'M' && c1 == 'A' && c2 == 'I' && c3 == 'L') | |
583 | 674 { |
1136 | 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 | |
1322 | 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 | |
527 | 697 } else { |
698 goto invalid; | |
699 } | |
1322 | 700 #if (NGX_MAIL_SSL) |
701 } else if (p - c == 8) { | |
527 | 702 |
1322 | 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 { | |
712 s->command = NGX_SMTP_STARTTLS; | |
713 | |
714 } else { | |
715 goto invalid; | |
716 } | |
717 #endif | |
527 | 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: | |
2309 | 753 if (s->args.nelts <= 10) { |
527 | 754 state = sw_argument; |
755 s->arg_start = p; | |
756 break; | |
757 } | |
758 goto invalid; | |
759 } | |
760 break; | |
761 | |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
762 case sw_argument: |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
763 switch (ch) { |
800 | 764 case ' ': |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
765 case CR: |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
766 case LF: |
501 | 767 arg = ngx_array_push(&s->args); |
768 if (arg == NULL) { | |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
769 return NGX_ERROR; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
770 } |
527 | 771 arg->len = p - s->arg_start; |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
772 arg->data = s->arg_start; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
773 s->arg_start = NULL; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
774 |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
775 switch (ch) { |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
776 case ' ': |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
777 state = sw_spaces_before_argument; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
778 break; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
779 case CR: |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
780 state = sw_almost_done; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
781 break; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
782 case LF: |
527 | 783 goto done; |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
784 } |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
785 break; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
786 |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
787 default: |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
788 break; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
789 } |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
790 break; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
791 |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
792 case sw_almost_done: |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
793 switch (ch) { |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
794 case LF: |
527 | 795 goto done; |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
796 default: |
527 | 797 goto invalid; |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
798 } |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
799 } |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
800 } |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
801 |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
802 s->buffer->pos = p; |
527 | 803 s->state = state; |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
804 |
527 | 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; | |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
815 } |
527 | 816 arg->len = s->arg_end - s->arg_start; |
817 arg->data = s->arg_start; | |
818 s->arg_start = NULL; | |
819 } | |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
820 |
1136 | 821 s->state = (s->command != NGX_SMTP_AUTH) ? sw_start : sw_argument; |
822 | |
527 | 823 return NGX_OK; |
824 | |
825 invalid: | |
826 | |
827 s->state = sw_start; | |
810 | 828 s->arg_start = NULL; |
527 | 829 |
1136 | 830 return NGX_MAIL_PARSE_INVALID_COMMAND; |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
831 } |
1479 | 832 |
833 | |
834 ngx_int_t | |
835 ngx_mail_auth_parse(ngx_mail_session_t *s, ngx_connection_t *c) | |
836 { | |
837 ngx_str_t *arg; | |
838 | |
839 #if (NGX_MAIL_SSL) | |
840 if (ngx_mail_starttls_only(s, c)) { | |
841 return NGX_MAIL_PARSE_INVALID_COMMAND; | |
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 | |
2495
a59b26eee816
compatibility with Microsoft's
Igor Sysoev <igor@sysoev.ru>
parents:
2309
diff
changeset
|
855 if (s->args.nelts == 2) { |
a59b26eee816
compatibility with Microsoft's
Igor Sysoev <igor@sysoev.ru>
parents:
2309
diff
changeset
|
856 return NGX_MAIL_AUTH_LOGIN_USERNAME; |
a59b26eee816
compatibility with Microsoft's
Igor Sysoev <igor@sysoev.ru>
parents:
2309
diff
changeset
|
857 } |
a59b26eee816
compatibility with Microsoft's
Igor Sysoev <igor@sysoev.ru>
parents:
2309
diff
changeset
|
858 |
1479 | 859 return NGX_MAIL_PARSE_INVALID_COMMAND; |
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 | |
873 return NGX_MAIL_PARSE_INVALID_COMMAND; | |
874 } | |
875 | |
876 if (arg[0].len == 8) { | |
877 | |
878 if (s->args.nelts != 1) { | |
879 return NGX_MAIL_PARSE_INVALID_COMMAND; | |
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 | |
887 return NGX_MAIL_PARSE_INVALID_COMMAND; | |
888 } |