Mercurial > hg > nginx
annotate src/mail/ngx_mail_parse.c @ 7839:3974f4e56a4e
Mail: fixed s->arg_start clearing on invalid IMAP commands.
Previously, s->arg_start was left intact after invalid IMAP commands,
and this might result in an argument incorrectly added to the following
command. Similarly, s->backslash was left intact as well, leading
to unneeded backslash removal.
For example (LFs from the client are explicitly shown as "<LF>"):
S: * OK IMAP4 ready
C: a01 login "\<LF>
S: a01 BAD invalid command
C: a0000000000\2 authenticate <LF>
S: a00000000002 aBAD invalid command
The backslash followed by LF generates invalid command with s->arg_start
and s->backslash set, the following command incorrectly treats anything
from the old s->arg_start to the space after the command as an argument,
and removes the backslash from the tag. If there is no space, s->arg_end
will be NULL.
Both things seem to be harmless though. In particular:
- This can be used to provide an incorrect argument to a command without
arguments. The only command which seems to look at the single argument
is AUTHENTICATE, and it checks the argument length before trying to
access it.
- Backslash removal uses the "end" pointer, and stops due to "src < end"
condition instead of scanning all the process memory if s->arg_end is
NULL (and arg[0].len is huge).
- There should be no backslashes in unquoted strings.
An obvious fix is to clear s->arg_start and s->backslash on invalid commands,
similarly to how it is done in POP3 parsing (added in 810:e3aa8f305d21) and
SMTP parsing.
This, however, makes it clear that s->arg_start handling in the "done"
label is wrong: s->arg_start cannot be legitimately set there, as it
is expected to be cleared in all possible cases when the "done" label is
reached. The relevant code is dead and will be removed by the following
change.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Wed, 19 May 2021 03:13:20 +0300 |
parents | 815c63581be4 |
children | 379d461eccf4 |
rev | line source |
---|---|
441
da8c5707af39
nginx-0.1.0-2004-09-28-12:34:51 import; set copyright and remove unused files
Igor Sysoev <igor@sysoev.ru>
parents:
422
diff
changeset
|
1 |
da8c5707af39
nginx-0.1.0-2004-09-28-12:34:51 import; set copyright and remove unused files
Igor Sysoev <igor@sysoev.ru>
parents:
422
diff
changeset
|
2 /* |
444
42d11f017717
nginx-0.1.0-2004-09-29-20:00:49 import; remove years from copyright
Igor Sysoev <igor@sysoev.ru>
parents:
441
diff
changeset
|
3 * Copyright (C) Igor Sysoev |
4412 | 4 * Copyright (C) Nginx, Inc. |
441
da8c5707af39
nginx-0.1.0-2004-09-28-12:34:51 import; set copyright and remove unused files
Igor Sysoev <igor@sysoev.ru>
parents:
422
diff
changeset
|
5 */ |
da8c5707af39
nginx-0.1.0-2004-09-28-12:34:51 import; set copyright and remove unused files
Igor Sysoev <igor@sysoev.ru>
parents:
422
diff
changeset
|
6 |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
7 |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
8 #include <ngx_config.h> |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
9 #include <ngx_core.h> |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
10 #include <ngx_event.h> |
1136 | 11 #include <ngx_mail.h> |
4759
4c36e15651f7
Fixed compilation with -Wmissing-prototypes.
Ruslan Ermilov <ru@nginx.com>
parents:
4412
diff
changeset
|
12 #include <ngx_mail_pop3_module.h> |
4c36e15651f7
Fixed compilation with -Wmissing-prototypes.
Ruslan Ermilov <ru@nginx.com>
parents:
4412
diff
changeset
|
13 #include <ngx_mail_imap_module.h> |
4c36e15651f7
Fixed compilation with -Wmissing-prototypes.
Ruslan Ermilov <ru@nginx.com>
parents:
4412
diff
changeset
|
14 #include <ngx_mail_smtp_module.h> |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
15 |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
16 |
1477 | 17 ngx_int_t |
18 ngx_mail_pop3_parse_command(ngx_mail_session_t *s) | |
1136 | 19 { |
20 u_char ch, *p, *c, c0, c1, c2, c3; | |
21 ngx_str_t *arg; | |
22 enum { | |
23 sw_start = 0, | |
7838
815c63581be4
Mail: POP3 pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7837
diff
changeset
|
24 sw_command, |
815c63581be4
Mail: POP3 pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7837
diff
changeset
|
25 sw_invalid, |
1136 | 26 sw_spaces_before_argument, |
27 sw_argument, | |
28 sw_almost_done | |
29 } state; | |
30 | |
31 state = s->state; | |
32 | |
33 for (p = s->buffer->pos; p < s->buffer->last; p++) { | |
34 ch = *p; | |
35 | |
36 switch (state) { | |
37 | |
38 /* POP3 command */ | |
39 case sw_start: | |
7838
815c63581be4
Mail: POP3 pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7837
diff
changeset
|
40 s->cmd_start = p; |
815c63581be4
Mail: POP3 pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7837
diff
changeset
|
41 state = sw_command; |
815c63581be4
Mail: POP3 pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7837
diff
changeset
|
42 |
815c63581be4
Mail: POP3 pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7837
diff
changeset
|
43 /* fall through */ |
815c63581be4
Mail: POP3 pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7837
diff
changeset
|
44 |
815c63581be4
Mail: POP3 pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7837
diff
changeset
|
45 case sw_command: |
1136 | 46 if (ch == ' ' || ch == CR || ch == LF) { |
7838
815c63581be4
Mail: POP3 pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7837
diff
changeset
|
47 c = s->cmd_start; |
1136 | 48 |
49 if (p - c == 4) { | |
50 | |
51 c0 = ngx_toupper(c[0]); | |
52 c1 = ngx_toupper(c[1]); | |
53 c2 = ngx_toupper(c[2]); | |
54 c3 = ngx_toupper(c[3]); | |
55 | |
56 if (c0 == 'U' && c1 == 'S' && c2 == 'E' && c3 == 'R') | |
57 { | |
58 s->command = NGX_POP3_USER; | |
59 | |
60 } else if (c0 == 'P' && c1 == 'A' && c2 == 'S' && c3 == 'S') | |
61 { | |
62 s->command = NGX_POP3_PASS; | |
63 | |
64 } else if (c0 == 'A' && c1 == 'P' && c2 == 'O' && c3 == 'P') | |
65 { | |
66 s->command = NGX_POP3_APOP; | |
67 | |
68 } else if (c0 == 'Q' && c1 == 'U' && c2 == 'I' && c3 == 'T') | |
69 { | |
70 s->command = NGX_POP3_QUIT; | |
71 | |
72 } else if (c0 == 'C' && c1 == 'A' && c2 == 'P' && c3 == 'A') | |
73 { | |
74 s->command = NGX_POP3_CAPA; | |
75 | |
76 } else if (c0 == 'A' && c1 == 'U' && c2 == 'T' && c3 == 'H') | |
77 { | |
78 s->command = NGX_POP3_AUTH; | |
79 | |
80 } else if (c0 == 'N' && c1 == 'O' && c2 == 'O' && c3 == 'P') | |
81 { | |
82 s->command = NGX_POP3_NOOP; | |
83 #if (NGX_MAIL_SSL) | |
84 } else if (c0 == 'S' && c1 == 'T' && c2 == 'L' && c3 == 'S') | |
85 { | |
86 s->command = NGX_POP3_STLS; | |
87 #endif | |
88 } else { | |
89 goto invalid; | |
90 } | |
91 | |
92 } else { | |
93 goto invalid; | |
94 } | |
95 | |
7838
815c63581be4
Mail: POP3 pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7837
diff
changeset
|
96 s->cmd.data = s->cmd_start; |
815c63581be4
Mail: POP3 pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7837
diff
changeset
|
97 s->cmd.len = p - s->cmd_start; |
815c63581be4
Mail: POP3 pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7837
diff
changeset
|
98 |
1136 | 99 switch (ch) { |
100 case ' ': | |
101 state = sw_spaces_before_argument; | |
102 break; | |
103 case CR: | |
104 state = sw_almost_done; | |
105 break; | |
106 case LF: | |
107 goto done; | |
108 } | |
109 break; | |
110 } | |
111 | |
112 if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z')) { | |
113 goto invalid; | |
114 } | |
115 | |
116 break; | |
117 | |
7838
815c63581be4
Mail: POP3 pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7837
diff
changeset
|
118 case sw_invalid: |
815c63581be4
Mail: POP3 pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7837
diff
changeset
|
119 goto invalid; |
815c63581be4
Mail: POP3 pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7837
diff
changeset
|
120 |
1136 | 121 case sw_spaces_before_argument: |
122 switch (ch) { | |
123 case ' ': | |
124 break; | |
125 case CR: | |
126 state = sw_almost_done; | |
127 s->arg_end = p; | |
128 break; | |
129 case LF: | |
130 s->arg_end = p; | |
131 goto done; | |
132 default: | |
133 if (s->args.nelts <= 2) { | |
134 state = sw_argument; | |
135 s->arg_start = p; | |
136 break; | |
137 } | |
138 goto invalid; | |
139 } | |
140 break; | |
141 | |
142 case sw_argument: | |
143 switch (ch) { | |
144 | |
145 case ' ': | |
146 | |
147 /* | |
148 * the space should be considered as part of the at username | |
149 * or password, but not of argument in other commands | |
150 */ | |
151 | |
152 if (s->command == NGX_POP3_USER | |
153 || s->command == NGX_POP3_PASS) | |
154 { | |
155 break; | |
156 } | |
157 | |
158 /* fall through */ | |
159 | |
160 case CR: | |
161 case LF: | |
162 arg = ngx_array_push(&s->args); | |
163 if (arg == NULL) { | |
164 return NGX_ERROR; | |
165 } | |
166 arg->len = p - s->arg_start; | |
167 arg->data = s->arg_start; | |
168 s->arg_start = NULL; | |
169 | |
170 switch (ch) { | |
171 case ' ': | |
172 state = sw_spaces_before_argument; | |
173 break; | |
174 case CR: | |
175 state = sw_almost_done; | |
176 break; | |
177 case LF: | |
178 goto done; | |
179 } | |
180 break; | |
181 | |
182 default: | |
183 break; | |
184 } | |
185 break; | |
186 | |
187 case sw_almost_done: | |
188 switch (ch) { | |
189 case LF: | |
190 goto done; | |
191 default: | |
192 goto invalid; | |
193 } | |
194 } | |
195 } | |
196 | |
197 s->buffer->pos = p; | |
198 s->state = state; | |
199 | |
200 return NGX_AGAIN; | |
201 | |
202 done: | |
203 | |
204 s->buffer->pos = p + 1; | |
205 | |
206 if (s->arg_start) { | |
207 arg = ngx_array_push(&s->args); | |
208 if (arg == NULL) { | |
209 return NGX_ERROR; | |
210 } | |
211 arg->len = s->arg_end - s->arg_start; | |
212 arg->data = s->arg_start; | |
213 s->arg_start = NULL; | |
214 } | |
215 | |
216 s->state = (s->command != NGX_POP3_AUTH) ? sw_start : sw_argument; | |
217 | |
218 return NGX_OK; | |
219 | |
220 invalid: | |
221 | |
7838
815c63581be4
Mail: POP3 pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7837
diff
changeset
|
222 s->state = sw_invalid; |
1136 | 223 s->arg_start = NULL; |
224 | |
7838
815c63581be4
Mail: POP3 pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7837
diff
changeset
|
225 /* skip invalid command till LF */ |
815c63581be4
Mail: POP3 pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7837
diff
changeset
|
226 |
815c63581be4
Mail: POP3 pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7837
diff
changeset
|
227 for ( /* void */ ; p < s->buffer->last; p++) { |
815c63581be4
Mail: POP3 pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7837
diff
changeset
|
228 if (*p == LF) { |
815c63581be4
Mail: POP3 pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7837
diff
changeset
|
229 s->state = sw_start; |
815c63581be4
Mail: POP3 pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7837
diff
changeset
|
230 s->buffer->pos = p + 1; |
815c63581be4
Mail: POP3 pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7837
diff
changeset
|
231 return NGX_MAIL_PARSE_INVALID_COMMAND; |
815c63581be4
Mail: POP3 pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7837
diff
changeset
|
232 } |
815c63581be4
Mail: POP3 pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7837
diff
changeset
|
233 } |
815c63581be4
Mail: POP3 pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7837
diff
changeset
|
234 |
815c63581be4
Mail: POP3 pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7837
diff
changeset
|
235 s->buffer->pos = p; |
815c63581be4
Mail: POP3 pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7837
diff
changeset
|
236 |
815c63581be4
Mail: POP3 pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7837
diff
changeset
|
237 return NGX_AGAIN; |
1136 | 238 } |
239 | |
240 | |
1477 | 241 ngx_int_t |
242 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
|
243 { |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
244 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
|
245 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
|
246 enum { |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
247 sw_start = 0, |
527 | 248 sw_spaces_before_command, |
249 sw_command, | |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
250 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
|
251 sw_argument, |
543 | 252 sw_backslash, |
527 | 253 sw_literal, |
543 | 254 sw_no_sync_literal_argument, |
527 | 255 sw_start_literal_argument, |
256 sw_literal_argument, | |
257 sw_end_literal_argument, | |
258 sw_almost_done | |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
259 } state; |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
260 |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
261 state = s->state; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
262 |
527 | 263 for (p = s->buffer->pos; p < s->buffer->last; p++) { |
264 ch = *p; | |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
265 |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
266 switch (state) { |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
267 |
527 | 268 /* IMAP tag */ |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
269 case sw_start: |
527 | 270 switch (ch) { |
271 case ' ': | |
272 s->tag.len = p - s->buffer->start + 1; | |
273 s->tag.data = s->buffer->start; | |
274 state = sw_spaces_before_command; | |
275 break; | |
276 case CR: | |
277 s->state = sw_start; | |
1136 | 278 return NGX_MAIL_PARSE_INVALID_COMMAND; |
527 | 279 case LF: |
280 s->state = sw_start; | |
1136 | 281 return NGX_MAIL_PARSE_INVALID_COMMAND; |
527 | 282 } |
283 break; | |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
284 |
527 | 285 case sw_spaces_before_command: |
286 switch (ch) { | |
287 case ' ': | |
288 break; | |
289 case CR: | |
290 s->state = sw_start; | |
1136 | 291 return NGX_MAIL_PARSE_INVALID_COMMAND; |
527 | 292 case LF: |
293 s->state = sw_start; | |
1136 | 294 return NGX_MAIL_PARSE_INVALID_COMMAND; |
527 | 295 default: |
296 s->cmd_start = p; | |
297 state = sw_command; | |
298 break; | |
299 } | |
300 break; | |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
301 |
527 | 302 case sw_command: |
303 if (ch == ' ' || ch == CR || ch == LF) { | |
304 | |
305 c = s->cmd_start; | |
306 | |
307 switch (p - c) { | |
308 | |
309 case 4: | |
310 if ((c[0] == 'N' || c[0] == 'n') | |
311 && (c[1] == 'O'|| c[1] == 'o') | |
312 && (c[2] == 'O'|| c[2] == 'o') | |
313 && (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
|
314 { |
527 | 315 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
|
316 |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
317 } else { |
527 | 318 goto invalid; |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
319 } |
527 | 320 break; |
321 | |
322 case 5: | |
323 if ((c[0] == 'L'|| c[0] == 'l') | |
324 && (c[1] == 'O'|| c[1] == 'o') | |
325 && (c[2] == 'G'|| c[2] == 'g') | |
326 && (c[3] == 'I'|| c[3] == 'i') | |
327 && (c[4] == 'N'|| c[4] == 'n')) | |
328 { | |
329 s->command = NGX_IMAP_LOGIN; | |
330 | |
331 } else { | |
332 goto invalid; | |
333 } | |
334 break; | |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
335 |
527 | 336 case 6: |
337 if ((c[0] == 'L'|| c[0] == 'l') | |
338 && (c[1] == 'O'|| c[1] == 'o') | |
339 && (c[2] == 'G'|| c[2] == 'g') | |
340 && (c[3] == 'O'|| c[3] == 'o') | |
341 && (c[4] == 'U'|| c[4] == 'u') | |
342 && (c[5] == 'T'|| c[5] == 't')) | |
343 { | |
344 s->command = NGX_IMAP_LOGOUT; | |
345 | |
346 } else { | |
347 goto invalid; | |
348 } | |
349 break; | |
350 | |
1136 | 351 #if (NGX_MAIL_SSL) |
583 | 352 case 8: |
353 if ((c[0] == 'S'|| c[0] == 's') | |
354 && (c[1] == 'T'|| c[1] == 't') | |
355 && (c[2] == 'A'|| c[2] == 'a') | |
356 && (c[3] == 'R'|| c[3] == 'r') | |
357 && (c[4] == 'T'|| c[4] == 't') | |
358 && (c[5] == 'T'|| c[5] == 't') | |
359 && (c[6] == 'L'|| c[6] == 'l') | |
360 && (c[7] == 'S'|| c[7] == 's')) | |
361 { | |
362 s->command = NGX_IMAP_STARTTLS; | |
363 | |
364 } else { | |
365 goto invalid; | |
366 } | |
367 break; | |
368 #endif | |
369 | |
527 | 370 case 10: |
371 if ((c[0] == 'C'|| c[0] == 'c') | |
372 && (c[1] == 'A'|| c[1] == 'a') | |
373 && (c[2] == 'P'|| c[2] == 'p') | |
374 && (c[3] == 'A'|| c[3] == 'a') | |
375 && (c[4] == 'B'|| c[4] == 'b') | |
376 && (c[5] == 'I'|| c[5] == 'i') | |
377 && (c[6] == 'L'|| c[6] == 'l') | |
378 && (c[7] == 'I'|| c[7] == 'i') | |
379 && (c[8] == 'T'|| c[8] == 't') | |
380 && (c[9] == 'Y'|| c[9] == 'y')) | |
381 { | |
382 s->command = NGX_IMAP_CAPABILITY; | |
383 | |
384 } else { | |
385 goto invalid; | |
386 } | |
387 break; | |
388 | |
1323 | 389 case 12: |
390 if ((c[0] == 'A'|| c[0] == 'a') | |
391 && (c[1] == 'U'|| c[1] == 'u') | |
392 && (c[2] == 'T'|| c[2] == 't') | |
393 && (c[3] == 'H'|| c[3] == 'h') | |
394 && (c[4] == 'E'|| c[4] == 'e') | |
395 && (c[5] == 'N'|| c[5] == 'n') | |
396 && (c[6] == 'T'|| c[6] == 't') | |
397 && (c[7] == 'I'|| c[7] == 'i') | |
398 && (c[8] == 'C'|| c[8] == 'c') | |
399 && (c[9] == 'A'|| c[9] == 'a') | |
400 && (c[10] == 'T'|| c[10] == 't') | |
401 && (c[11] == 'E'|| c[11] == 'e')) | |
402 { | |
403 s->command = NGX_IMAP_AUTHENTICATE; | |
404 | |
405 } else { | |
406 goto invalid; | |
407 } | |
408 break; | |
409 | |
527 | 410 default: |
411 goto invalid; | |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
412 } |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
413 |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
414 switch (ch) { |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
415 case ' ': |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
416 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
|
417 break; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
418 case CR: |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
419 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
|
420 break; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
421 case LF: |
527 | 422 goto done; |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
423 } |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
424 break; |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
425 } |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
426 |
527 | 427 if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z')) { |
428 goto invalid; | |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
429 } |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
430 |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
431 break; |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
432 |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
433 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
|
434 switch (ch) { |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
435 case ' ': |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
436 break; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
437 case CR: |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
438 state = sw_almost_done; |
527 | 439 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
|
440 break; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
441 case LF: |
527 | 442 s->arg_end = p; |
443 goto done; | |
444 case '"': | |
445 if (s->args.nelts <= 2) { | |
446 s->quoted = 1; | |
447 s->arg_start = p + 1; | |
448 state = sw_argument; | |
449 break; | |
450 } | |
451 goto invalid; | |
452 case '{': | |
453 if (s->args.nelts <= 2) { | |
454 state = sw_literal; | |
455 break; | |
456 } | |
457 goto invalid; | |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
458 default: |
527 | 459 if (s->args.nelts <= 2) { |
460 s->arg_start = p; | |
461 state = sw_argument; | |
462 break; | |
463 } | |
464 goto invalid; | |
465 } | |
466 break; | |
467 | |
468 case sw_argument: | |
1405
fdd064faf26a
escape " ", "%", and %00-%1F in login and password
Igor Sysoev <igor@sysoev.ru>
parents:
1323
diff
changeset
|
469 if (ch == ' ' && s->quoted) { |
fdd064faf26a
escape " ", "%", and %00-%1F in login and password
Igor Sysoev <igor@sysoev.ru>
parents:
1323
diff
changeset
|
470 break; |
fdd064faf26a
escape " ", "%", and %00-%1F in login and password
Igor Sysoev <igor@sysoev.ru>
parents:
1323
diff
changeset
|
471 } |
fdd064faf26a
escape " ", "%", and %00-%1F in login and password
Igor Sysoev <igor@sysoev.ru>
parents:
1323
diff
changeset
|
472 |
527 | 473 switch (ch) { |
474 case '"': | |
475 if (!s->quoted) { | |
476 break; | |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
477 } |
527 | 478 s->quoted = 0; |
479 /* fall through */ | |
480 case ' ': | |
481 case CR: | |
482 case LF: | |
483 arg = ngx_array_push(&s->args); | |
484 if (arg == NULL) { | |
485 return NGX_ERROR; | |
486 } | |
487 arg->len = p - s->arg_start; | |
488 arg->data = s->arg_start; | |
489 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
|
490 |
527 | 491 switch (ch) { |
492 case '"': | |
493 case ' ': | |
494 state = sw_spaces_before_argument; | |
495 break; | |
496 case CR: | |
497 state = sw_almost_done; | |
498 break; | |
499 case LF: | |
500 goto done; | |
501 } | |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
502 break; |
543 | 503 case '\\': |
504 if (s->quoted) { | |
505 s->backslash = 1; | |
506 state = sw_backslash; | |
507 } | |
508 break; | |
509 } | |
510 break; | |
511 | |
512 case sw_backslash: | |
513 switch (ch) { | |
514 case CR: | |
515 case LF: | |
516 goto invalid; | |
517 default: | |
518 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
|
519 } |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
520 break; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
521 |
527 | 522 case sw_literal: |
523 if (ch >= '0' && ch <= '9') { | |
524 s->literal_len = s->literal_len * 10 + (ch - '0'); | |
525 break; | |
526 } | |
527 if (ch == '}') { | |
528 state = sw_start_literal_argument; | |
529 break; | |
530 } | |
543 | 531 if (ch == '+') { |
532 state = sw_no_sync_literal_argument; | |
533 break; | |
534 } | |
535 goto invalid; | |
536 | |
537 case sw_no_sync_literal_argument: | |
538 if (ch == '}') { | |
539 s->no_sync_literal = 1; | |
540 state = sw_start_literal_argument; | |
541 break; | |
542 } | |
527 | 543 goto invalid; |
544 | |
545 case sw_start_literal_argument: | |
546 switch (ch) { | |
547 case CR: | |
548 break; | |
549 case LF: | |
550 s->buffer->pos = p + 1; | |
551 s->arg_start = p + 1; | |
543 | 552 if (s->no_sync_literal == 0) { |
553 s->state = sw_literal_argument; | |
554 return NGX_IMAP_NEXT; | |
555 } | |
556 state = sw_literal_argument; | |
557 s->no_sync_literal = 0; | |
558 break; | |
559 default: | |
560 goto invalid; | |
527 | 561 } |
543 | 562 break; |
527 | 563 |
564 case sw_literal_argument: | |
529 | 565 if (s->literal_len && --s->literal_len) { |
527 | 566 break; |
567 } | |
568 | |
569 arg = ngx_array_push(&s->args); | |
570 if (arg == NULL) { | |
571 return NGX_ERROR; | |
572 } | |
573 arg->len = p + 1 - s->arg_start; | |
574 arg->data = s->arg_start; | |
575 s->arg_start = NULL; | |
576 state = sw_end_literal_argument; | |
577 | |
578 break; | |
579 | |
580 case sw_end_literal_argument: | |
581 switch (ch) { | |
582 case '{': | |
583 if (s->args.nelts <= 2) { | |
584 state = sw_literal; | |
585 break; | |
586 } | |
587 goto invalid; | |
588 case CR: | |
589 state = sw_almost_done; | |
590 break; | |
591 case LF: | |
592 goto done; | |
593 default: | |
529 | 594 state = sw_spaces_before_argument; |
595 break; | |
527 | 596 } |
597 break; | |
598 | |
599 case sw_almost_done: | |
600 switch (ch) { | |
601 case LF: | |
602 goto done; | |
603 default: | |
604 goto invalid; | |
605 } | |
606 } | |
607 } | |
608 | |
609 s->buffer->pos = p; | |
610 s->state = state; | |
611 | |
612 return NGX_AGAIN; | |
613 | |
614 done: | |
615 | |
616 s->buffer->pos = p + 1; | |
617 | |
618 if (s->arg_start) { | |
619 arg = ngx_array_push(&s->args); | |
620 if (arg == NULL) { | |
621 return NGX_ERROR; | |
622 } | |
623 arg->len = s->arg_end - s->arg_start; | |
624 arg->data = s->arg_start; | |
543 | 625 |
527 | 626 s->arg_start = NULL; |
627 s->cmd_start = NULL; | |
628 s->quoted = 0; | |
543 | 629 s->no_sync_literal = 0; |
527 | 630 s->literal_len = 0; |
631 } | |
632 | |
1323 | 633 s->state = (s->command != NGX_IMAP_AUTHENTICATE) ? sw_start : sw_argument; |
527 | 634 |
635 return NGX_OK; | |
636 | |
637 invalid: | |
638 | |
639 s->state = sw_start; | |
7839
3974f4e56a4e
Mail: fixed s->arg_start clearing on invalid IMAP commands.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7838
diff
changeset
|
640 s->arg_start = NULL; |
527 | 641 s->quoted = 0; |
7839
3974f4e56a4e
Mail: fixed s->arg_start clearing on invalid IMAP commands.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7838
diff
changeset
|
642 s->backslash = 0; |
543 | 643 s->no_sync_literal = 0; |
527 | 644 s->literal_len = 0; |
645 | |
1136 | 646 return NGX_MAIL_PARSE_INVALID_COMMAND; |
527 | 647 } |
648 | |
649 | |
1477 | 650 ngx_int_t |
651 ngx_mail_smtp_parse_command(ngx_mail_session_t *s) | |
527 | 652 { |
653 u_char ch, *p, *c, c0, c1, c2, c3; | |
654 ngx_str_t *arg; | |
655 enum { | |
656 sw_start = 0, | |
5398
04e43d03e153
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
5246
diff
changeset
|
657 sw_command, |
04e43d03e153
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
5246
diff
changeset
|
658 sw_invalid, |
527 | 659 sw_spaces_before_argument, |
660 sw_argument, | |
661 sw_almost_done | |
662 } state; | |
663 | |
664 state = s->state; | |
665 | |
666 for (p = s->buffer->pos; p < s->buffer->last; p++) { | |
667 ch = *p; | |
668 | |
669 switch (state) { | |
670 | |
1136 | 671 /* SMTP command */ |
527 | 672 case sw_start: |
5398
04e43d03e153
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
5246
diff
changeset
|
673 s->cmd_start = p; |
04e43d03e153
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
5246
diff
changeset
|
674 state = sw_command; |
04e43d03e153
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
5246
diff
changeset
|
675 |
04e43d03e153
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
5246
diff
changeset
|
676 /* fall through */ |
04e43d03e153
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
5246
diff
changeset
|
677 |
04e43d03e153
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
5246
diff
changeset
|
678 case sw_command: |
527 | 679 if (ch == ' ' || ch == CR || ch == LF) { |
5398
04e43d03e153
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
5246
diff
changeset
|
680 c = s->cmd_start; |
527 | 681 |
682 if (p - c == 4) { | |
683 | |
684 c0 = ngx_toupper(c[0]); | |
685 c1 = ngx_toupper(c[1]); | |
686 c2 = ngx_toupper(c[2]); | |
687 c3 = ngx_toupper(c[3]); | |
688 | |
1136 | 689 if (c0 == 'H' && c1 == 'E' && c2 == 'L' && c3 == 'O') |
527 | 690 { |
1136 | 691 s->command = NGX_SMTP_HELO; |
527 | 692 |
1136 | 693 } else if (c0 == 'E' && c1 == 'H' && c2 == 'L' && c3 == 'O') |
800 | 694 { |
1136 | 695 s->command = NGX_SMTP_EHLO; |
800 | 696 |
527 | 697 } else if (c0 == 'Q' && c1 == 'U' && c2 == 'I' && c3 == 'T') |
698 { | |
1136 | 699 s->command = NGX_SMTP_QUIT; |
527 | 700 |
809 | 701 } else if (c0 == 'A' && c1 == 'U' && c2 == 'T' && c3 == 'H') |
702 { | |
1136 | 703 s->command = NGX_SMTP_AUTH; |
809 | 704 |
527 | 705 } else if (c0 == 'N' && c1 == 'O' && c2 == 'O' && c3 == 'P') |
706 { | |
1136 | 707 s->command = NGX_SMTP_NOOP; |
708 | |
709 } else if (c0 == 'M' && c1 == 'A' && c2 == 'I' && c3 == 'L') | |
583 | 710 { |
1136 | 711 s->command = NGX_SMTP_MAIL; |
712 | |
713 } else if (c0 == 'R' && c1 == 'S' && c2 == 'E' && c3 == 'T') | |
714 { | |
715 s->command = NGX_SMTP_RSET; | |
716 | |
1322 | 717 } else if (c0 == 'R' && c1 == 'C' && c2 == 'P' && c3 == 'T') |
718 { | |
719 s->command = NGX_SMTP_RCPT; | |
720 | |
721 } else if (c0 == 'V' && c1 == 'R' && c2 == 'F' && c3 == 'Y') | |
722 { | |
723 s->command = NGX_SMTP_VRFY; | |
724 | |
725 } else if (c0 == 'E' && c1 == 'X' && c2 == 'P' && c3 == 'N') | |
726 { | |
727 s->command = NGX_SMTP_EXPN; | |
728 | |
729 } else if (c0 == 'H' && c1 == 'E' && c2 == 'L' && c3 == 'P') | |
730 { | |
731 s->command = NGX_SMTP_HELP; | |
732 | |
527 | 733 } else { |
734 goto invalid; | |
735 } | |
1322 | 736 #if (NGX_MAIL_SSL) |
737 } else if (p - c == 8) { | |
527 | 738 |
1322 | 739 if ((c[0] == 'S'|| c[0] == 's') |
740 && (c[1] == 'T'|| c[1] == 't') | |
741 && (c[2] == 'A'|| c[2] == 'a') | |
742 && (c[3] == 'R'|| c[3] == 'r') | |
743 && (c[4] == 'T'|| c[4] == 't') | |
744 && (c[5] == 'T'|| c[5] == 't') | |
745 && (c[6] == 'L'|| c[6] == 'l') | |
746 && (c[7] == 'S'|| c[7] == 's')) | |
747 { | |
748 s->command = NGX_SMTP_STARTTLS; | |
749 | |
750 } else { | |
751 goto invalid; | |
752 } | |
753 #endif | |
527 | 754 } else { |
755 goto invalid; | |
756 } | |
757 | |
5398
04e43d03e153
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
5246
diff
changeset
|
758 s->cmd.data = s->cmd_start; |
04e43d03e153
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
5246
diff
changeset
|
759 s->cmd.len = p - s->cmd_start; |
04e43d03e153
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
5246
diff
changeset
|
760 |
527 | 761 switch (ch) { |
762 case ' ': | |
763 state = sw_spaces_before_argument; | |
764 break; | |
765 case CR: | |
766 state = sw_almost_done; | |
767 break; | |
768 case LF: | |
769 goto done; | |
770 } | |
771 break; | |
772 } | |
773 | |
774 if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z')) { | |
775 goto invalid; | |
776 } | |
777 | |
778 break; | |
779 | |
5398
04e43d03e153
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
5246
diff
changeset
|
780 case sw_invalid: |
04e43d03e153
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
5246
diff
changeset
|
781 goto invalid; |
04e43d03e153
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
5246
diff
changeset
|
782 |
527 | 783 case sw_spaces_before_argument: |
784 switch (ch) { | |
785 case ' ': | |
786 break; | |
787 case CR: | |
788 state = sw_almost_done; | |
789 s->arg_end = p; | |
790 break; | |
791 case LF: | |
792 s->arg_end = p; | |
793 goto done; | |
794 default: | |
2309 | 795 if (s->args.nelts <= 10) { |
527 | 796 state = sw_argument; |
797 s->arg_start = p; | |
798 break; | |
799 } | |
800 goto invalid; | |
801 } | |
802 break; | |
803 | |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
804 case sw_argument: |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
805 switch (ch) { |
800 | 806 case ' ': |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
807 case CR: |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
808 case LF: |
501 | 809 arg = ngx_array_push(&s->args); |
810 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
|
811 return NGX_ERROR; |
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 = 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
|
814 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
|
815 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
|
816 |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
817 switch (ch) { |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
818 case ' ': |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
819 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
|
820 break; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
821 case CR: |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
822 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
|
823 break; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
824 case LF: |
527 | 825 goto done; |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
826 } |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
827 break; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
828 |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
829 default: |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
830 break; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
831 } |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
832 break; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
833 |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
834 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
|
835 switch (ch) { |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
836 case LF: |
527 | 837 goto done; |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
838 default: |
527 | 839 goto invalid; |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
840 } |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
841 } |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
842 } |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
843 |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
844 s->buffer->pos = p; |
527 | 845 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
|
846 |
527 | 847 return NGX_AGAIN; |
848 | |
849 done: | |
850 | |
851 s->buffer->pos = p + 1; | |
852 | |
853 if (s->arg_start) { | |
854 arg = ngx_array_push(&s->args); | |
855 if (arg == NULL) { | |
856 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
|
857 } |
527 | 858 arg->len = s->arg_end - s->arg_start; |
859 arg->data = s->arg_start; | |
860 s->arg_start = NULL; | |
861 } | |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
862 |
1136 | 863 s->state = (s->command != NGX_SMTP_AUTH) ? sw_start : sw_argument; |
864 | |
527 | 865 return NGX_OK; |
866 | |
867 invalid: | |
868 | |
5398
04e43d03e153
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
5246
diff
changeset
|
869 s->state = sw_invalid; |
810 | 870 s->arg_start = NULL; |
527 | 871 |
5398
04e43d03e153
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
5246
diff
changeset
|
872 /* skip invalid command till LF */ |
04e43d03e153
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
5246
diff
changeset
|
873 |
7837
ba8a8299b904
Mail: optimized discarding invalid SMTP commands.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7836
diff
changeset
|
874 for ( /* void */ ; p < s->buffer->last; p++) { |
5398
04e43d03e153
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
5246
diff
changeset
|
875 if (*p == LF) { |
04e43d03e153
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
5246
diff
changeset
|
876 s->state = sw_start; |
7836
6a81d96d3733
Mail: fixed handling of invalid SMTP commands split between reads.
Maxim Dounin <mdounin@mdounin.ru>
parents:
6774
diff
changeset
|
877 s->buffer->pos = p + 1; |
6a81d96d3733
Mail: fixed handling of invalid SMTP commands split between reads.
Maxim Dounin <mdounin@mdounin.ru>
parents:
6774
diff
changeset
|
878 return NGX_MAIL_PARSE_INVALID_COMMAND; |
5398
04e43d03e153
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
5246
diff
changeset
|
879 } |
04e43d03e153
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
5246
diff
changeset
|
880 } |
04e43d03e153
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
5246
diff
changeset
|
881 |
04e43d03e153
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
5246
diff
changeset
|
882 s->buffer->pos = p; |
04e43d03e153
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
5246
diff
changeset
|
883 |
7836
6a81d96d3733
Mail: fixed handling of invalid SMTP commands split between reads.
Maxim Dounin <mdounin@mdounin.ru>
parents:
6774
diff
changeset
|
884 return NGX_AGAIN; |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
885 } |
1479 | 886 |
887 | |
888 ngx_int_t | |
889 ngx_mail_auth_parse(ngx_mail_session_t *s, ngx_connection_t *c) | |
890 { | |
891 ngx_str_t *arg; | |
892 | |
893 #if (NGX_MAIL_SSL) | |
894 if (ngx_mail_starttls_only(s, c)) { | |
895 return NGX_MAIL_PARSE_INVALID_COMMAND; | |
896 } | |
897 #endif | |
898 | |
5246
b6562f98bfd8
Mail: fixed possible uninitialized memory access.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4759
diff
changeset
|
899 if (s->args.nelts == 0) { |
b6562f98bfd8
Mail: fixed possible uninitialized memory access.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4759
diff
changeset
|
900 return NGX_MAIL_PARSE_INVALID_COMMAND; |
b6562f98bfd8
Mail: fixed possible uninitialized memory access.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4759
diff
changeset
|
901 } |
b6562f98bfd8
Mail: fixed possible uninitialized memory access.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4759
diff
changeset
|
902 |
1479 | 903 arg = s->args.elts; |
904 | |
905 if (arg[0].len == 5) { | |
906 | |
907 if (ngx_strncasecmp(arg[0].data, (u_char *) "LOGIN", 5) == 0) { | |
908 | |
909 if (s->args.nelts == 1) { | |
910 return NGX_MAIL_AUTH_LOGIN; | |
911 } | |
912 | |
2495
a59b26eee816
compatibility with Microsoft's
Igor Sysoev <igor@sysoev.ru>
parents:
2309
diff
changeset
|
913 if (s->args.nelts == 2) { |
a59b26eee816
compatibility with Microsoft's
Igor Sysoev <igor@sysoev.ru>
parents:
2309
diff
changeset
|
914 return NGX_MAIL_AUTH_LOGIN_USERNAME; |
a59b26eee816
compatibility with Microsoft's
Igor Sysoev <igor@sysoev.ru>
parents:
2309
diff
changeset
|
915 } |
a59b26eee816
compatibility with Microsoft's
Igor Sysoev <igor@sysoev.ru>
parents:
2309
diff
changeset
|
916 |
1479 | 917 return NGX_MAIL_PARSE_INVALID_COMMAND; |
918 } | |
919 | |
920 if (ngx_strncasecmp(arg[0].data, (u_char *) "PLAIN", 5) == 0) { | |
921 | |
922 if (s->args.nelts == 1) { | |
923 return NGX_MAIL_AUTH_PLAIN; | |
924 } | |
925 | |
926 if (s->args.nelts == 2) { | |
927 return ngx_mail_auth_plain(s, c, 1); | |
928 } | |
929 } | |
930 | |
931 return NGX_MAIL_PARSE_INVALID_COMMAND; | |
932 } | |
933 | |
934 if (arg[0].len == 8) { | |
935 | |
6774
bcb107bb89cd
Mail: support SASL EXTERNAL (RFC 4422).
Rob N ★ <robn@fastmail.com>
parents:
5398
diff
changeset
|
936 if (ngx_strncasecmp(arg[0].data, (u_char *) "CRAM-MD5", 8) == 0) { |
bcb107bb89cd
Mail: support SASL EXTERNAL (RFC 4422).
Rob N ★ <robn@fastmail.com>
parents:
5398
diff
changeset
|
937 |
bcb107bb89cd
Mail: support SASL EXTERNAL (RFC 4422).
Rob N ★ <robn@fastmail.com>
parents:
5398
diff
changeset
|
938 if (s->args.nelts != 1) { |
bcb107bb89cd
Mail: support SASL EXTERNAL (RFC 4422).
Rob N ★ <robn@fastmail.com>
parents:
5398
diff
changeset
|
939 return NGX_MAIL_PARSE_INVALID_COMMAND; |
bcb107bb89cd
Mail: support SASL EXTERNAL (RFC 4422).
Rob N ★ <robn@fastmail.com>
parents:
5398
diff
changeset
|
940 } |
bcb107bb89cd
Mail: support SASL EXTERNAL (RFC 4422).
Rob N ★ <robn@fastmail.com>
parents:
5398
diff
changeset
|
941 |
bcb107bb89cd
Mail: support SASL EXTERNAL (RFC 4422).
Rob N ★ <robn@fastmail.com>
parents:
5398
diff
changeset
|
942 return NGX_MAIL_AUTH_CRAM_MD5; |
1479 | 943 } |
944 | |
6774
bcb107bb89cd
Mail: support SASL EXTERNAL (RFC 4422).
Rob N ★ <robn@fastmail.com>
parents:
5398
diff
changeset
|
945 if (ngx_strncasecmp(arg[0].data, (u_char *) "EXTERNAL", 8) == 0) { |
bcb107bb89cd
Mail: support SASL EXTERNAL (RFC 4422).
Rob N ★ <robn@fastmail.com>
parents:
5398
diff
changeset
|
946 |
bcb107bb89cd
Mail: support SASL EXTERNAL (RFC 4422).
Rob N ★ <robn@fastmail.com>
parents:
5398
diff
changeset
|
947 if (s->args.nelts == 1) { |
bcb107bb89cd
Mail: support SASL EXTERNAL (RFC 4422).
Rob N ★ <robn@fastmail.com>
parents:
5398
diff
changeset
|
948 return NGX_MAIL_AUTH_EXTERNAL; |
bcb107bb89cd
Mail: support SASL EXTERNAL (RFC 4422).
Rob N ★ <robn@fastmail.com>
parents:
5398
diff
changeset
|
949 } |
bcb107bb89cd
Mail: support SASL EXTERNAL (RFC 4422).
Rob N ★ <robn@fastmail.com>
parents:
5398
diff
changeset
|
950 |
bcb107bb89cd
Mail: support SASL EXTERNAL (RFC 4422).
Rob N ★ <robn@fastmail.com>
parents:
5398
diff
changeset
|
951 if (s->args.nelts == 2) { |
bcb107bb89cd
Mail: support SASL EXTERNAL (RFC 4422).
Rob N ★ <robn@fastmail.com>
parents:
5398
diff
changeset
|
952 return ngx_mail_auth_external(s, c, 1); |
bcb107bb89cd
Mail: support SASL EXTERNAL (RFC 4422).
Rob N ★ <robn@fastmail.com>
parents:
5398
diff
changeset
|
953 } |
1479 | 954 } |
6774
bcb107bb89cd
Mail: support SASL EXTERNAL (RFC 4422).
Rob N ★ <robn@fastmail.com>
parents:
5398
diff
changeset
|
955 |
bcb107bb89cd
Mail: support SASL EXTERNAL (RFC 4422).
Rob N ★ <robn@fastmail.com>
parents:
5398
diff
changeset
|
956 return NGX_MAIL_PARSE_INVALID_COMMAND; |
1479 | 957 } |
958 | |
959 return NGX_MAIL_PARSE_INVALID_COMMAND; | |
960 } |