Mercurial > hg > nginx
annotate src/mail/ngx_mail_parse.c @ 4692:489839d07b38
Fixed "sendmsg() failed" alerts on HP-UX.
HP-UX needs _HPUX_ALT_XOPEN_SOCKET_API to be defined to be able to
use various POSIX versions of networking functions. Notably sendmsg()
resulted in "sendmsg() failed (9: Bad file number)" alerts without it.
See xopen_networking(7) for more details.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Mon, 18 Jun 2012 14:11:29 +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 } |