Mercurial > hg > nginx-mail
annotate src/mail/ngx_mail_pop3_handler.c @ 571:5938746e70c2 PATCH_NGINX_MAIL_0_8
Mail: get rid of ugly protocol check in ngx_mail_auth_parse().
Instead, use index of argument which holds authentication mechanism name. For
IMAP and POP3 it's 0, for SMTP - 1 as SMTP preserves command in first argument
to allow pipelining support.
While here, add check that we actually have argument holding authentication
mechanism name. Currently IMAP has no appropriate checks before calling
ngx_mail_auth_parse() which results in possible access of uninitialized
memory.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Sun, 27 Sep 2009 00:52:15 +0400 |
parents | 2580fe1c5a9a |
children | 0b460e61bdcd |
rev | line source |
---|---|
336 | 1 |
2 /* | |
3 * Copyright (C) Igor Sysoev | |
4 */ | |
5 | |
6 | |
7 #include <ngx_config.h> | |
8 #include <ngx_core.h> | |
9 #include <ngx_event.h> | |
10 #include <ngx_mail.h> | |
11 #include <ngx_mail_pop3_module.h> | |
12 | |
13 | |
14 static ngx_int_t ngx_mail_pop3_user(ngx_mail_session_t *s, ngx_connection_t *c); | |
15 static ngx_int_t ngx_mail_pop3_pass(ngx_mail_session_t *s, ngx_connection_t *c); | |
16 static ngx_int_t ngx_mail_pop3_capa(ngx_mail_session_t *s, ngx_connection_t *c, | |
17 ngx_int_t stls); | |
18 static ngx_int_t ngx_mail_pop3_stls(ngx_mail_session_t *s, ngx_connection_t *c); | |
19 static ngx_int_t ngx_mail_pop3_apop(ngx_mail_session_t *s, ngx_connection_t *c); | |
20 static ngx_int_t ngx_mail_pop3_auth(ngx_mail_session_t *s, ngx_connection_t *c); | |
21 | |
22 | |
23 static u_char pop3_greeting[] = "+OK POP3 ready" CRLF; | |
24 static u_char pop3_ok[] = "+OK" CRLF; | |
25 static u_char pop3_next[] = "+ " CRLF; | |
26 static u_char pop3_username[] = "+ VXNlcm5hbWU6" CRLF; | |
27 static u_char pop3_password[] = "+ UGFzc3dvcmQ6" CRLF; | |
28 static u_char pop3_invalid_command[] = "-ERR invalid command" CRLF; | |
29 | |
30 | |
31 void | |
32 ngx_mail_pop3_init_session(ngx_mail_session_t *s, ngx_connection_t *c) | |
33 { | |
34 u_char *p; | |
35 ngx_mail_core_srv_conf_t *cscf; | |
36 ngx_mail_pop3_srv_conf_t *pscf; | |
37 | |
38 pscf = ngx_mail_get_module_srv_conf(s, ngx_mail_pop3_module); | |
39 cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); | |
40 | |
41 if (pscf->auth_methods | |
42 & (NGX_MAIL_AUTH_APOP_ENABLED|NGX_MAIL_AUTH_CRAM_MD5_ENABLED)) | |
43 { | |
44 if (ngx_mail_salt(s, c, cscf) != NGX_OK) { | |
45 ngx_mail_session_internal_server_error(s); | |
46 return; | |
47 } | |
48 | |
382 | 49 s->out.data = ngx_pnalloc(c->pool, sizeof(pop3_greeting) + s->salt.len); |
336 | 50 if (s->out.data == NULL) { |
51 ngx_mail_session_internal_server_error(s); | |
52 return; | |
53 } | |
54 | |
55 p = ngx_cpymem(s->out.data, pop3_greeting, sizeof(pop3_greeting) - 3); | |
56 *p++ = ' '; | |
57 p = ngx_cpymem(p, s->salt.data, s->salt.len); | |
58 | |
59 s->out.len = p - s->out.data; | |
60 | |
61 } else { | |
62 s->out.len = sizeof(pop3_greeting) - 1; | |
63 s->out.data = pop3_greeting; | |
64 } | |
65 | |
66 c->read->handler = ngx_mail_pop3_init_protocol; | |
67 | |
68 ngx_add_timer(c->read, cscf->timeout); | |
69 | |
459 | 70 if (ngx_handle_read_event(c->read, 0) != NGX_OK) { |
336 | 71 ngx_mail_close_connection(c); |
72 } | |
73 | |
74 ngx_mail_send(c->write); | |
75 } | |
76 | |
77 | |
78 void | |
79 ngx_mail_pop3_init_protocol(ngx_event_t *rev) | |
80 { | |
81 ngx_connection_t *c; | |
82 ngx_mail_session_t *s; | |
83 | |
84 c = rev->data; | |
85 | |
86 c->log->action = "in auth state"; | |
87 | |
88 if (rev->timedout) { | |
89 ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out"); | |
90 c->timedout = 1; | |
91 ngx_mail_close_connection(c); | |
92 return; | |
93 } | |
94 | |
95 s = c->data; | |
96 | |
97 if (s->buffer == NULL) { | |
98 if (ngx_array_init(&s->args, c->pool, 2, sizeof(ngx_str_t)) | |
99 == NGX_ERROR) | |
100 { | |
101 ngx_mail_session_internal_server_error(s); | |
102 return; | |
103 } | |
104 | |
105 s->buffer = ngx_create_temp_buf(c->pool, 128); | |
106 if (s->buffer == NULL) { | |
107 ngx_mail_session_internal_server_error(s); | |
108 return; | |
109 } | |
110 } | |
111 | |
112 s->mail_state = ngx_pop3_start; | |
113 c->read->handler = ngx_mail_pop3_auth_state; | |
114 | |
115 ngx_mail_pop3_auth_state(rev); | |
116 } | |
117 | |
118 | |
119 void | |
120 ngx_mail_pop3_auth_state(ngx_event_t *rev) | |
121 { | |
122 ngx_int_t rc; | |
123 ngx_connection_t *c; | |
124 ngx_mail_session_t *s; | |
125 | |
126 c = rev->data; | |
127 s = c->data; | |
128 | |
129 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "pop3 auth state"); | |
130 | |
131 if (rev->timedout) { | |
132 ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out"); | |
133 c->timedout = 1; | |
134 ngx_mail_close_connection(c); | |
135 return; | |
136 } | |
137 | |
138 if (s->out.len) { | |
139 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "pop3 send handler busy"); | |
140 s->blocked = 1; | |
141 return; | |
142 } | |
143 | |
144 s->blocked = 0; | |
145 | |
146 rc = ngx_mail_read_command(s, c); | |
147 | |
148 if (rc == NGX_AGAIN || rc == NGX_ERROR) { | |
149 return; | |
150 } | |
151 | |
152 s->out.len = sizeof(pop3_ok) - 1; | |
153 s->out.data = pop3_ok; | |
154 | |
155 if (rc == NGX_OK) { | |
156 switch (s->mail_state) { | |
157 | |
158 case ngx_pop3_start: | |
159 | |
160 switch (s->command) { | |
161 | |
162 case NGX_POP3_USER: | |
163 rc = ngx_mail_pop3_user(s, c); | |
164 break; | |
165 | |
166 case NGX_POP3_CAPA: | |
167 rc = ngx_mail_pop3_capa(s, c, 1); | |
168 break; | |
169 | |
170 case NGX_POP3_APOP: | |
171 rc = ngx_mail_pop3_apop(s, c); | |
172 break; | |
173 | |
174 case NGX_POP3_AUTH: | |
175 rc = ngx_mail_pop3_auth(s, c); | |
176 break; | |
177 | |
178 case NGX_POP3_QUIT: | |
179 s->quit = 1; | |
180 break; | |
181 | |
182 case NGX_POP3_NOOP: | |
183 break; | |
184 | |
185 case NGX_POP3_STLS: | |
186 rc = ngx_mail_pop3_stls(s, c); | |
187 break; | |
188 | |
189 default: | |
190 rc = NGX_MAIL_PARSE_INVALID_COMMAND; | |
191 s->mail_state = ngx_pop3_start; | |
192 break; | |
193 } | |
194 | |
195 break; | |
196 | |
197 case ngx_pop3_user: | |
198 | |
199 switch (s->command) { | |
200 | |
201 case NGX_POP3_PASS: | |
202 rc = ngx_mail_pop3_pass(s, c); | |
203 break; | |
204 | |
205 case NGX_POP3_CAPA: | |
206 rc = ngx_mail_pop3_capa(s, c, 0); | |
207 break; | |
208 | |
209 case NGX_POP3_QUIT: | |
210 s->quit = 1; | |
211 break; | |
212 | |
213 case NGX_POP3_NOOP: | |
214 break; | |
215 | |
216 default: | |
217 rc = NGX_MAIL_PARSE_INVALID_COMMAND; | |
218 s->mail_state = ngx_pop3_start; | |
219 break; | |
220 } | |
221 | |
222 break; | |
223 | |
224 /* suppress warinings */ | |
225 case ngx_pop3_passwd: | |
226 break; | |
227 | |
228 case ngx_pop3_auth_login_username: | |
468
2580fe1c5a9a
Mail: support for smtp auth login with username.
Maxim Dounin <mdounin@mdounin.ru>
parents:
459
diff
changeset
|
229 rc = ngx_mail_auth_login_username(s, c, 0); |
336 | 230 |
231 s->out.len = sizeof(pop3_password) - 1; | |
232 s->out.data = pop3_password; | |
233 s->mail_state = ngx_pop3_auth_login_password; | |
234 break; | |
235 | |
236 case ngx_pop3_auth_login_password: | |
237 rc = ngx_mail_auth_login_password(s, c); | |
238 break; | |
239 | |
240 case ngx_pop3_auth_plain: | |
241 rc = ngx_mail_auth_plain(s, c, 0); | |
242 break; | |
243 | |
244 case ngx_pop3_auth_cram_md5: | |
245 rc = ngx_mail_auth_cram_md5(s, c); | |
246 break; | |
247 } | |
248 } | |
249 | |
250 switch (rc) { | |
251 | |
252 case NGX_DONE: | |
253 ngx_mail_auth(s, c); | |
254 return; | |
255 | |
256 case NGX_ERROR: | |
257 ngx_mail_session_internal_server_error(s); | |
258 return; | |
259 | |
260 case NGX_MAIL_PARSE_INVALID_COMMAND: | |
261 s->mail_state = ngx_pop3_start; | |
262 s->state = 0; | |
263 | |
264 s->out.len = sizeof(pop3_invalid_command) - 1; | |
265 s->out.data = pop3_invalid_command; | |
266 | |
267 /* fall through */ | |
268 | |
269 case NGX_OK: | |
270 | |
271 s->args.nelts = 0; | |
272 s->buffer->pos = s->buffer->start; | |
273 s->buffer->last = s->buffer->start; | |
274 | |
275 if (s->state) { | |
276 s->arg_start = s->buffer->start; | |
277 } | |
278 | |
279 ngx_mail_send(c->write); | |
280 } | |
281 } | |
282 | |
283 static ngx_int_t | |
284 ngx_mail_pop3_user(ngx_mail_session_t *s, ngx_connection_t *c) | |
285 { | |
356 | 286 ngx_str_t *arg; |
336 | 287 |
288 #if (NGX_MAIL_SSL) | |
289 if (ngx_mail_starttls_only(s, c)) { | |
290 return NGX_MAIL_PARSE_INVALID_COMMAND; | |
291 } | |
292 #endif | |
293 | |
294 if (s->args.nelts != 1) { | |
295 return NGX_MAIL_PARSE_INVALID_COMMAND; | |
296 } | |
297 | |
298 arg = s->args.elts; | |
299 s->login.len = arg[0].len; | |
382 | 300 s->login.data = ngx_pnalloc(c->pool, s->login.len); |
336 | 301 if (s->login.data == NULL) { |
302 return NGX_ERROR; | |
303 } | |
304 | |
305 ngx_memcpy(s->login.data, arg[0].data, s->login.len); | |
306 | |
307 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0, | |
308 "pop3 login: \"%V\"", &s->login); | |
309 | |
310 s->mail_state = ngx_pop3_user; | |
311 | |
312 return NGX_OK; | |
313 } | |
314 | |
315 | |
316 static ngx_int_t | |
317 ngx_mail_pop3_pass(ngx_mail_session_t *s, ngx_connection_t *c) | |
318 { | |
319 ngx_str_t *arg; | |
320 | |
321 if (s->args.nelts != 1) { | |
322 return NGX_MAIL_PARSE_INVALID_COMMAND; | |
323 } | |
324 | |
325 arg = s->args.elts; | |
326 s->passwd.len = arg[0].len; | |
382 | 327 s->passwd.data = ngx_pnalloc(c->pool, s->passwd.len); |
336 | 328 if (s->passwd.data == NULL) { |
329 return NGX_ERROR; | |
330 } | |
331 | |
332 ngx_memcpy(s->passwd.data, arg[0].data, s->passwd.len); | |
333 | |
334 #if (NGX_DEBUG_MAIL_PASSWD) | |
335 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0, | |
336 "pop3 passwd: \"%V\"", &s->passwd); | |
337 #endif | |
338 | |
339 return NGX_DONE; | |
340 } | |
341 | |
342 | |
343 static ngx_int_t | |
344 ngx_mail_pop3_capa(ngx_mail_session_t *s, ngx_connection_t *c, ngx_int_t stls) | |
345 { | |
346 ngx_mail_pop3_srv_conf_t *pscf; | |
347 | |
348 pscf = ngx_mail_get_module_srv_conf(s, ngx_mail_pop3_module); | |
349 | |
350 #if (NGX_MAIL_SSL) | |
351 | |
352 if (stls && c->ssl == NULL) { | |
356 | 353 ngx_mail_ssl_conf_t *sslcf; |
354 | |
336 | 355 sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module); |
356 | |
357 if (sslcf->starttls == NGX_MAIL_STARTTLS_ON) { | |
358 s->out = pscf->starttls_capability; | |
359 return NGX_OK; | |
360 } | |
361 | |
362 if (sslcf->starttls == NGX_MAIL_STARTTLS_ONLY) { | |
363 s->out = pscf->starttls_only_capability; | |
364 return NGX_OK; | |
365 } | |
366 } | |
367 | |
368 #endif | |
369 | |
370 s->out = pscf->capability; | |
371 return NGX_OK; | |
372 } | |
373 | |
374 | |
375 static ngx_int_t | |
376 ngx_mail_pop3_stls(ngx_mail_session_t *s, ngx_connection_t *c) | |
377 { | |
378 #if (NGX_MAIL_SSL) | |
379 ngx_mail_ssl_conf_t *sslcf; | |
380 | |
381 if (c->ssl == NULL) { | |
382 sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module); | |
383 if (sslcf->starttls) { | |
384 c->read->handler = ngx_mail_starttls_handler; | |
385 return NGX_OK; | |
386 } | |
387 } | |
388 | |
389 #endif | |
390 | |
391 return NGX_MAIL_PARSE_INVALID_COMMAND; | |
392 } | |
393 | |
394 | |
395 static ngx_int_t | |
396 ngx_mail_pop3_apop(ngx_mail_session_t *s, ngx_connection_t *c) | |
397 { | |
398 ngx_str_t *arg; | |
399 ngx_mail_pop3_srv_conf_t *pscf; | |
400 | |
401 #if (NGX_MAIL_SSL) | |
402 if (ngx_mail_starttls_only(s, c)) { | |
403 return NGX_MAIL_PARSE_INVALID_COMMAND; | |
404 } | |
405 #endif | |
406 | |
407 if (s->args.nelts != 2) { | |
408 return NGX_MAIL_PARSE_INVALID_COMMAND; | |
409 } | |
410 | |
411 pscf = ngx_mail_get_module_srv_conf(s, ngx_mail_pop3_module); | |
412 | |
413 if (!(pscf->auth_methods & NGX_MAIL_AUTH_APOP_ENABLED)) { | |
414 return NGX_MAIL_PARSE_INVALID_COMMAND; | |
415 } | |
416 | |
417 arg = s->args.elts; | |
418 | |
419 s->login.len = arg[0].len; | |
382 | 420 s->login.data = ngx_pnalloc(c->pool, s->login.len); |
336 | 421 if (s->login.data == NULL) { |
422 return NGX_ERROR; | |
423 } | |
424 | |
425 ngx_memcpy(s->login.data, arg[0].data, s->login.len); | |
426 | |
427 s->passwd.len = arg[1].len; | |
382 | 428 s->passwd.data = ngx_pnalloc(c->pool, s->passwd.len); |
336 | 429 if (s->passwd.data == NULL) { |
430 return NGX_ERROR; | |
431 } | |
432 | |
433 ngx_memcpy(s->passwd.data, arg[1].data, s->passwd.len); | |
434 | |
435 ngx_log_debug2(NGX_LOG_DEBUG_MAIL, c->log, 0, | |
436 "pop3 apop: \"%V\" \"%V\"", &s->login, &s->passwd); | |
437 | |
438 s->auth_method = NGX_MAIL_AUTH_APOP; | |
439 | |
440 return NGX_DONE; | |
441 } | |
442 | |
443 | |
444 static ngx_int_t | |
445 ngx_mail_pop3_auth(ngx_mail_session_t *s, ngx_connection_t *c) | |
446 { | |
447 ngx_int_t rc; | |
448 ngx_mail_pop3_srv_conf_t *pscf; | |
449 | |
450 #if (NGX_MAIL_SSL) | |
451 if (ngx_mail_starttls_only(s, c)) { | |
452 return NGX_MAIL_PARSE_INVALID_COMMAND; | |
453 } | |
454 #endif | |
455 | |
456 pscf = ngx_mail_get_module_srv_conf(s, ngx_mail_pop3_module); | |
457 | |
458 if (s->args.nelts == 0) { | |
459 s->out = pscf->auth_capability; | |
460 s->state = 0; | |
461 | |
462 return NGX_OK; | |
463 } | |
464 | |
571
5938746e70c2
Mail: get rid of ugly protocol check in ngx_mail_auth_parse().
Maxim Dounin <mdounin@mdounin.ru>
parents:
468
diff
changeset
|
465 rc = ngx_mail_auth_parse(s, c, 0); |
336 | 466 |
467 switch (rc) { | |
468 | |
469 case NGX_MAIL_AUTH_LOGIN: | |
470 | |
471 s->out.len = sizeof(pop3_username) - 1; | |
472 s->out.data = pop3_username; | |
473 s->mail_state = ngx_pop3_auth_login_username; | |
474 | |
475 return NGX_OK; | |
476 | |
468
2580fe1c5a9a
Mail: support for smtp auth login with username.
Maxim Dounin <mdounin@mdounin.ru>
parents:
459
diff
changeset
|
477 case NGX_MAIL_AUTH_LOGIN_USERNAME: |
2580fe1c5a9a
Mail: support for smtp auth login with username.
Maxim Dounin <mdounin@mdounin.ru>
parents:
459
diff
changeset
|
478 |
2580fe1c5a9a
Mail: support for smtp auth login with username.
Maxim Dounin <mdounin@mdounin.ru>
parents:
459
diff
changeset
|
479 s->out.len = sizeof(pop3_password) - 1; |
2580fe1c5a9a
Mail: support for smtp auth login with username.
Maxim Dounin <mdounin@mdounin.ru>
parents:
459
diff
changeset
|
480 s->out.data = pop3_password; |
2580fe1c5a9a
Mail: support for smtp auth login with username.
Maxim Dounin <mdounin@mdounin.ru>
parents:
459
diff
changeset
|
481 s->mail_state = ngx_pop3_auth_login_password; |
2580fe1c5a9a
Mail: support for smtp auth login with username.
Maxim Dounin <mdounin@mdounin.ru>
parents:
459
diff
changeset
|
482 |
2580fe1c5a9a
Mail: support for smtp auth login with username.
Maxim Dounin <mdounin@mdounin.ru>
parents:
459
diff
changeset
|
483 return ngx_mail_auth_login_username(s, c, 1); |
2580fe1c5a9a
Mail: support for smtp auth login with username.
Maxim Dounin <mdounin@mdounin.ru>
parents:
459
diff
changeset
|
484 |
336 | 485 case NGX_MAIL_AUTH_PLAIN: |
486 | |
487 s->out.len = sizeof(pop3_next) - 1; | |
488 s->out.data = pop3_next; | |
489 s->mail_state = ngx_pop3_auth_plain; | |
490 | |
491 return NGX_OK; | |
492 | |
493 case NGX_MAIL_AUTH_CRAM_MD5: | |
494 | |
495 if (!(pscf->auth_methods & NGX_MAIL_AUTH_CRAM_MD5_ENABLED)) { | |
496 return NGX_MAIL_PARSE_INVALID_COMMAND; | |
497 } | |
498 | |
499 if (ngx_mail_auth_cram_md5_salt(s, c, "+ ", 2) == NGX_OK) { | |
500 s->mail_state = ngx_pop3_auth_cram_md5; | |
501 return NGX_OK; | |
502 } | |
503 | |
504 return NGX_ERROR; | |
505 } | |
506 | |
507 return rc; | |
508 } |