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