Mercurial > hg > nginx
annotate src/mail/ngx_mail_parse.c @ 2165:cbf6f2eb57ad
backout both r2162 and r2128 and implement a new fix
author | Igor Sysoev <igor@sysoev.ru> |
---|---|
date | Tue, 12 Aug 2008 12:04:49 +0000 |
parents | 2647950e047f |
children | 8156bc03982a 62c95a6b143b |
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 |
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
|
4 */ |
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 |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
6 |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
7 #include <ngx_config.h> |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
8 #include <ngx_core.h> |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
9 #include <ngx_event.h> |
1136 | 10 #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
|
11 |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
12 |
1477 | 13 ngx_int_t |
14 ngx_mail_pop3_parse_command(ngx_mail_session_t *s) | |
1136 | 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 | |
1477 | 211 ngx_int_t |
212 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
|
213 { |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
214 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
|
215 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
|
216 enum { |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
217 sw_start = 0, |
527 | 218 sw_spaces_before_command, |
219 sw_command, | |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
220 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
|
221 sw_argument, |
543 | 222 sw_backslash, |
527 | 223 sw_literal, |
543 | 224 sw_no_sync_literal_argument, |
527 | 225 sw_start_literal_argument, |
226 sw_literal_argument, | |
227 sw_end_literal_argument, | |
228 sw_almost_done | |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
229 } state; |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
230 |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
231 state = s->state; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
232 |
527 | 233 for (p = s->buffer->pos; p < s->buffer->last; p++) { |
234 ch = *p; | |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
235 |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
236 switch (state) { |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
237 |
527 | 238 /* IMAP tag */ |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
239 case sw_start: |
527 | 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; | |
1136 | 248 return NGX_MAIL_PARSE_INVALID_COMMAND; |
527 | 249 case LF: |
250 s->state = sw_start; | |
1136 | 251 return NGX_MAIL_PARSE_INVALID_COMMAND; |
527 | 252 } |
253 break; | |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
254 |
527 | 255 case sw_spaces_before_command: |
256 switch (ch) { | |
257 case ' ': | |
258 break; | |
259 case CR: | |
260 s->state = sw_start; | |
1136 | 261 return NGX_MAIL_PARSE_INVALID_COMMAND; |
527 | 262 case LF: |
263 s->state = sw_start; | |
1136 | 264 return NGX_MAIL_PARSE_INVALID_COMMAND; |
527 | 265 default: |
266 s->cmd_start = p; | |
267 state = sw_command; | |
268 break; | |
269 } | |
270 break; | |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
271 |
527 | 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')) | |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
284 { |
527 | 285 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
|
286 |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
287 } else { |
527 | 288 goto invalid; |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
289 } |
527 | 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; | |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
305 |
527 | 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 | |
1136 | 321 #if (NGX_MAIL_SSL) |
583 | 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 | |
527 | 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 | |
1323 | 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 | |
527 | 380 default: |
381 goto invalid; | |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
382 } |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
383 |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
384 switch (ch) { |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
385 case ' ': |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
386 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
|
387 break; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
388 case CR: |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
389 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
|
390 break; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
391 case LF: |
527 | 392 goto done; |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
393 } |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
394 break; |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
395 } |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
396 |
527 | 397 if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z')) { |
398 goto invalid; | |
417
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 |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
401 break; |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
402 |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
403 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
|
404 switch (ch) { |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
405 case ' ': |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
406 break; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
407 case CR: |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
408 state = sw_almost_done; |
527 | 409 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
|
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 LF: |
527 | 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; | |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
428 default: |
527 | 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: | |
1405
fdd064faf26a
escape " ", "%", and %00-%1F in login and password
Igor Sysoev <igor@sysoev.ru>
parents:
1323
diff
changeset
|
439 if (ch == ' ' && s->quoted) { |
fdd064faf26a
escape " ", "%", and %00-%1F in login and password
Igor Sysoev <igor@sysoev.ru>
parents:
1323
diff
changeset
|
440 break; |
fdd064faf26a
escape " ", "%", and %00-%1F in login and password
Igor Sysoev <igor@sysoev.ru>
parents:
1323
diff
changeset
|
441 } |
fdd064faf26a
escape " ", "%", and %00-%1F in login and password
Igor Sysoev <igor@sysoev.ru>
parents:
1323
diff
changeset
|
442 |
527 | 443 switch (ch) { |
444 case '"': | |
445 if (!s->quoted) { | |
446 break; | |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
447 } |
527 | 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; | |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
460 |
527 | 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 } | |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
472 break; |
543 | 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; | |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
489 } |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
490 break; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
491 |
527 | 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 } | |
543 | 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 } | |
527 | 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; | |
543 | 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; | |
527 | 531 } |
543 | 532 break; |
527 | 533 |
534 case sw_literal_argument: | |
529 | 535 if (s->literal_len && --s->literal_len) { |
527 | 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: | |
529 | 564 state = sw_spaces_before_argument; |
565 break; | |
527 | 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; | |
543 | 595 |
527 | 596 s->arg_start = NULL; |
597 s->cmd_start = NULL; | |
598 s->quoted = 0; | |
543 | 599 s->no_sync_literal = 0; |
527 | 600 s->literal_len = 0; |
601 } | |
602 | |
1323 | 603 s->state = (s->command != NGX_IMAP_AUTHENTICATE) ? sw_start : sw_argument; |
527 | 604 |
605 return NGX_OK; | |
606 | |
607 invalid: | |
608 | |
609 s->state = sw_start; | |
610 s->quoted = 0; | |
543 | 611 s->no_sync_literal = 0; |
527 | 612 s->literal_len = 0; |
613 | |
1136 | 614 return NGX_MAIL_PARSE_INVALID_COMMAND; |
527 | 615 } |
616 | |
617 | |
1477 | 618 ngx_int_t |
619 ngx_mail_smtp_parse_command(ngx_mail_session_t *s) | |
527 | 620 { |
621 u_char ch, *p, *c, c0, c1, c2, c3; | |
622 ngx_str_t *arg; | |
623 enum { | |
624 sw_start = 0, | |
625 sw_spaces_before_argument, | |
626 sw_argument, | |
627 sw_almost_done | |
628 } state; | |
629 | |
630 state = s->state; | |
631 | |
632 for (p = s->buffer->pos; p < s->buffer->last; p++) { | |
633 ch = *p; | |
634 | |
635 switch (state) { | |
636 | |
1136 | 637 /* SMTP command */ |
527 | 638 case sw_start: |
639 if (ch == ' ' || ch == CR || ch == LF) { | |
640 c = s->buffer->start; | |
641 | |
642 if (p - c == 4) { | |
643 | |
644 c0 = ngx_toupper(c[0]); | |
645 c1 = ngx_toupper(c[1]); | |
646 c2 = ngx_toupper(c[2]); | |
647 c3 = ngx_toupper(c[3]); | |
648 | |
1136 | 649 if (c0 == 'H' && c1 == 'E' && c2 == 'L' && c3 == 'O') |
527 | 650 { |
1136 | 651 s->command = NGX_SMTP_HELO; |
527 | 652 |
1136 | 653 } else if (c0 == 'E' && c1 == 'H' && c2 == 'L' && c3 == 'O') |
800 | 654 { |
1136 | 655 s->command = NGX_SMTP_EHLO; |
800 | 656 |
527 | 657 } else if (c0 == 'Q' && c1 == 'U' && c2 == 'I' && c3 == 'T') |
658 { | |
1136 | 659 s->command = NGX_SMTP_QUIT; |
527 | 660 |
809 | 661 } else if (c0 == 'A' && c1 == 'U' && c2 == 'T' && c3 == 'H') |
662 { | |
1136 | 663 s->command = NGX_SMTP_AUTH; |
809 | 664 |
527 | 665 } else if (c0 == 'N' && c1 == 'O' && c2 == 'O' && c3 == 'P') |
666 { | |
1136 | 667 s->command = NGX_SMTP_NOOP; |
668 | |
669 } else if (c0 == 'M' && c1 == 'A' && c2 == 'I' && c3 == 'L') | |
583 | 670 { |
1136 | 671 s->command = NGX_SMTP_MAIL; |
672 | |
673 } else if (c0 == 'R' && c1 == 'S' && c2 == 'E' && c3 == 'T') | |
674 { | |
675 s->command = NGX_SMTP_RSET; | |
676 | |
1322 | 677 } else if (c0 == 'R' && c1 == 'C' && c2 == 'P' && c3 == 'T') |
678 { | |
679 s->command = NGX_SMTP_RCPT; | |
680 | |
681 } else if (c0 == 'V' && c1 == 'R' && c2 == 'F' && c3 == 'Y') | |
682 { | |
683 s->command = NGX_SMTP_VRFY; | |
684 | |
685 } else if (c0 == 'E' && c1 == 'X' && c2 == 'P' && c3 == 'N') | |
686 { | |
687 s->command = NGX_SMTP_EXPN; | |
688 | |
689 } else if (c0 == 'H' && c1 == 'E' && c2 == 'L' && c3 == 'P') | |
690 { | |
691 s->command = NGX_SMTP_HELP; | |
692 | |
527 | 693 } else { |
694 goto invalid; | |
695 } | |
1322 | 696 #if (NGX_MAIL_SSL) |
697 } else if (p - c == 8) { | |
527 | 698 |
1322 | 699 if ((c[0] == 'S'|| c[0] == 's') |
700 && (c[1] == 'T'|| c[1] == 't') | |
701 && (c[2] == 'A'|| c[2] == 'a') | |
702 && (c[3] == 'R'|| c[3] == 'r') | |
703 && (c[4] == 'T'|| c[4] == 't') | |
704 && (c[5] == 'T'|| c[5] == 't') | |
705 && (c[6] == 'L'|| c[6] == 'l') | |
706 && (c[7] == 'S'|| c[7] == 's')) | |
707 { | |
708 s->command = NGX_SMTP_STARTTLS; | |
709 | |
710 } else { | |
711 goto invalid; | |
712 } | |
713 #endif | |
527 | 714 } else { |
715 goto invalid; | |
716 } | |
717 | |
718 switch (ch) { | |
719 case ' ': | |
720 state = sw_spaces_before_argument; | |
721 break; | |
722 case CR: | |
723 state = sw_almost_done; | |
724 break; | |
725 case LF: | |
726 goto done; | |
727 } | |
728 break; | |
729 } | |
730 | |
731 if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z')) { | |
732 goto invalid; | |
733 } | |
734 | |
735 break; | |
736 | |
737 case sw_spaces_before_argument: | |
738 switch (ch) { | |
739 case ' ': | |
740 break; | |
741 case CR: | |
742 state = sw_almost_done; | |
743 s->arg_end = p; | |
744 break; | |
745 case LF: | |
746 s->arg_end = p; | |
747 goto done; | |
748 default: | |
749 if (s->args.nelts <= 2) { | |
750 state = sw_argument; | |
751 s->arg_start = p; | |
752 break; | |
753 } | |
754 goto invalid; | |
755 } | |
756 break; | |
757 | |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
758 case sw_argument: |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
759 switch (ch) { |
800 | 760 case ' ': |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
761 case CR: |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
762 case LF: |
501 | 763 arg = ngx_array_push(&s->args); |
764 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
|
765 return NGX_ERROR; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
766 } |
527 | 767 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
|
768 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
|
769 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
|
770 |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
771 switch (ch) { |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
772 case ' ': |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
773 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
|
774 break; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
775 case CR: |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
776 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
|
777 break; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
778 case LF: |
527 | 779 goto done; |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
780 } |
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 |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
783 default: |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
784 break; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
785 } |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
786 break; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
787 |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
788 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
|
789 switch (ch) { |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
790 case LF: |
527 | 791 goto done; |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
792 default: |
527 | 793 goto invalid; |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
794 } |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
795 } |
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 |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
798 s->buffer->pos = p; |
527 | 799 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
|
800 |
527 | 801 return NGX_AGAIN; |
802 | |
803 done: | |
804 | |
805 s->buffer->pos = p + 1; | |
806 | |
807 if (s->arg_start) { | |
808 arg = ngx_array_push(&s->args); | |
809 if (arg == NULL) { | |
810 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
|
811 } |
527 | 812 arg->len = s->arg_end - s->arg_start; |
813 arg->data = s->arg_start; | |
814 s->arg_start = NULL; | |
815 } | |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
816 |
1136 | 817 s->state = (s->command != NGX_SMTP_AUTH) ? sw_start : sw_argument; |
818 | |
527 | 819 return NGX_OK; |
820 | |
821 invalid: | |
822 | |
823 s->state = sw_start; | |
810 | 824 s->arg_start = NULL; |
527 | 825 |
1136 | 826 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
|
827 } |
1479 | 828 |
829 | |
830 ngx_int_t | |
831 ngx_mail_auth_parse(ngx_mail_session_t *s, ngx_connection_t *c) | |
832 { | |
833 ngx_str_t *arg; | |
834 | |
835 #if (NGX_MAIL_SSL) | |
836 if (ngx_mail_starttls_only(s, c)) { | |
837 return NGX_MAIL_PARSE_INVALID_COMMAND; | |
838 } | |
839 #endif | |
840 | |
841 arg = s->args.elts; | |
842 | |
843 if (arg[0].len == 5) { | |
844 | |
845 if (ngx_strncasecmp(arg[0].data, (u_char *) "LOGIN", 5) == 0) { | |
846 | |
847 if (s->args.nelts == 1) { | |
848 return NGX_MAIL_AUTH_LOGIN; | |
849 } | |
850 | |
851 return NGX_MAIL_PARSE_INVALID_COMMAND; | |
852 } | |
853 | |
854 if (ngx_strncasecmp(arg[0].data, (u_char *) "PLAIN", 5) == 0) { | |
855 | |
856 if (s->args.nelts == 1) { | |
857 return NGX_MAIL_AUTH_PLAIN; | |
858 } | |
859 | |
860 if (s->args.nelts == 2) { | |
861 return ngx_mail_auth_plain(s, c, 1); | |
862 } | |
863 } | |
864 | |
865 return NGX_MAIL_PARSE_INVALID_COMMAND; | |
866 } | |
867 | |
868 if (arg[0].len == 8) { | |
869 | |
870 if (s->args.nelts != 1) { | |
871 return NGX_MAIL_PARSE_INVALID_COMMAND; | |
872 } | |
873 | |
874 if (ngx_strncasecmp(arg[0].data, (u_char *) "CRAM-MD5", 8) == 0) { | |
875 return NGX_MAIL_AUTH_CRAM_MD5; | |
876 } | |
877 } | |
878 | |
879 return NGX_MAIL_PARSE_INVALID_COMMAND; | |
880 } |