Mercurial > hg > nginx
annotate src/mail/ngx_mail_parse.c @ 4192:61e4af19df9f
Autoindex: escape '?' in file names.
For files with '?' in their names autoindex generated links with '?' not
escaped. This resulted in effectively truncated links as '?' indicates
query string start.
This is an updated version of the patch originally posted at [1]. It
introduces generic NGX_ESCAPE_URI_COMPONENT which escapes everything but
unreserved characters as per RFC 3986. This approach also renders unneeded
special colon processing (as colon is percent-encoded now), it's dropped
accordingly.
[1] http://nginx.org/pipermail/nginx-devel/2010-February/000112.html
Reported by Konstantin Leonov.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Tue, 11 Oct 2011 17:56:51 +0000 |
parents | a59b26eee816 |
children | d620f497c50f |
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: | |
2309 | 749 if (s->args.nelts <= 10) { |
527 | 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 | |
2495
a59b26eee816
compatibility with Microsoft's
Igor Sysoev <igor@sysoev.ru>
parents:
2309
diff
changeset
|
851 if (s->args.nelts == 2) { |
a59b26eee816
compatibility with Microsoft's
Igor Sysoev <igor@sysoev.ru>
parents:
2309
diff
changeset
|
852 return NGX_MAIL_AUTH_LOGIN_USERNAME; |
a59b26eee816
compatibility with Microsoft's
Igor Sysoev <igor@sysoev.ru>
parents:
2309
diff
changeset
|
853 } |
a59b26eee816
compatibility with Microsoft's
Igor Sysoev <igor@sysoev.ru>
parents:
2309
diff
changeset
|
854 |
1479 | 855 return NGX_MAIL_PARSE_INVALID_COMMAND; |
856 } | |
857 | |
858 if (ngx_strncasecmp(arg[0].data, (u_char *) "PLAIN", 5) == 0) { | |
859 | |
860 if (s->args.nelts == 1) { | |
861 return NGX_MAIL_AUTH_PLAIN; | |
862 } | |
863 | |
864 if (s->args.nelts == 2) { | |
865 return ngx_mail_auth_plain(s, c, 1); | |
866 } | |
867 } | |
868 | |
869 return NGX_MAIL_PARSE_INVALID_COMMAND; | |
870 } | |
871 | |
872 if (arg[0].len == 8) { | |
873 | |
874 if (s->args.nelts != 1) { | |
875 return NGX_MAIL_PARSE_INVALID_COMMAND; | |
876 } | |
877 | |
878 if (ngx_strncasecmp(arg[0].data, (u_char *) "CRAM-MD5", 8) == 0) { | |
879 return NGX_MAIL_AUTH_CRAM_MD5; | |
880 } | |
881 } | |
882 | |
883 return NGX_MAIL_PARSE_INVALID_COMMAND; | |
884 } |