3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Nginx, Inc.
8 #include <ngx_config.h>
10 #include <ngx_event.h>
12 #include <ngx_mail_pop3_module.h>
15 static ngx_int_t
ngx_mail_pop3_user(ngx_mail_session_t
*s
, ngx_connection_t
*c
);
16 static ngx_int_t
ngx_mail_pop3_pass(ngx_mail_session_t
*s
, ngx_connection_t
*c
);
17 static ngx_int_t
ngx_mail_pop3_capa(ngx_mail_session_t
*s
, ngx_connection_t
*c
,
19 static ngx_int_t
ngx_mail_pop3_stls(ngx_mail_session_t
*s
, ngx_connection_t
*c
);
20 static ngx_int_t
ngx_mail_pop3_apop(ngx_mail_session_t
*s
, ngx_connection_t
*c
);
21 static ngx_int_t
ngx_mail_pop3_auth(ngx_mail_session_t
*s
, ngx_connection_t
*c
);
24 static u_char pop3_greeting
[] = "+OK POP3 ready" CRLF
;
25 static u_char pop3_ok
[] = "+OK" CRLF
;
26 static u_char pop3_next
[] = "+ " CRLF
;
27 static u_char pop3_username
[] = "+ VXNlcm5hbWU6" CRLF
;
28 static u_char pop3_password
[] = "+ UGFzc3dvcmQ6" CRLF
;
29 static u_char pop3_invalid_command
[] = "-ERR invalid command" CRLF
;
33 ngx_mail_pop3_init_session(ngx_mail_session_t
*s
, ngx_connection_t
*c
)
36 ngx_mail_core_srv_conf_t
*cscf
;
37 ngx_mail_pop3_srv_conf_t
*pscf
;
39 pscf
= ngx_mail_get_module_srv_conf(s
, ngx_mail_pop3_module
);
40 cscf
= ngx_mail_get_module_srv_conf(s
, ngx_mail_core_module
);
42 if (pscf
->auth_methods
43 & (NGX_MAIL_AUTH_APOP_ENABLED
|NGX_MAIL_AUTH_CRAM_MD5_ENABLED
))
45 if (ngx_mail_salt(s
, c
, cscf
) != NGX_OK
) {
46 ngx_mail_session_internal_server_error(s
);
50 s
->out
.data
= ngx_pnalloc(c
->pool
, sizeof(pop3_greeting
) + s
->salt
.len
);
51 if (s
->out
.data
== NULL
) {
52 ngx_mail_session_internal_server_error(s
);
56 p
= ngx_cpymem(s
->out
.data
, pop3_greeting
, sizeof(pop3_greeting
) - 3);
58 p
= ngx_cpymem(p
, s
->salt
.data
, s
->salt
.len
);
60 s
->out
.len
= p
- s
->out
.data
;
63 ngx_str_set(&s
->out
, pop3_greeting
);
66 c
->read
->handler
= ngx_mail_pop3_init_protocol
;
68 ngx_add_timer(c
->read
, cscf
->timeout
);
70 if (ngx_handle_read_event(c
->read
, 0) != NGX_OK
) {
71 ngx_mail_close_connection(c
);
74 ngx_mail_send(c
->write
);
79 ngx_mail_pop3_init_protocol(ngx_event_t
*rev
)
82 ngx_mail_session_t
*s
;
86 c
->log
->action
= "in auth state";
89 ngx_log_error(NGX_LOG_INFO
, c
->log
, NGX_ETIMEDOUT
, "client timed out");
91 ngx_mail_close_connection(c
);
97 if (s
->buffer
== NULL
) {
98 if (ngx_array_init(&s
->args
, c
->pool
, 2, sizeof(ngx_str_t
))
101 ngx_mail_session_internal_server_error(s
);
105 s
->buffer
= ngx_create_temp_buf(c
->pool
, 128);
106 if (s
->buffer
== NULL
) {
107 ngx_mail_session_internal_server_error(s
);
112 s
->mail_state
= ngx_pop3_start
;
113 c
->read
->handler
= ngx_mail_pop3_auth_state
;
115 ngx_mail_pop3_auth_state(rev
);
120 ngx_mail_pop3_auth_state(ngx_event_t
*rev
)
124 ngx_mail_session_t
*s
;
129 ngx_log_debug0(NGX_LOG_DEBUG_MAIL
, c
->log
, 0, "pop3 auth state");
132 ngx_log_error(NGX_LOG_INFO
, c
->log
, NGX_ETIMEDOUT
, "client timed out");
134 ngx_mail_close_connection(c
);
139 ngx_log_debug0(NGX_LOG_DEBUG_MAIL
, c
->log
, 0, "pop3 send handler busy");
146 rc
= ngx_mail_read_command(s
, c
);
148 if (rc
== NGX_AGAIN
|| rc
== NGX_ERROR
) {
152 ngx_str_set(&s
->out
, pop3_ok
);
155 switch (s
->mail_state
) {
159 switch (s
->command
) {
162 rc
= ngx_mail_pop3_user(s
, c
);
166 rc
= ngx_mail_pop3_capa(s
, c
, 1);
170 rc
= ngx_mail_pop3_apop(s
, c
);
174 rc
= ngx_mail_pop3_auth(s
, c
);
185 rc
= ngx_mail_pop3_stls(s
, c
);
189 rc
= NGX_MAIL_PARSE_INVALID_COMMAND
;
197 switch (s
->command
) {
200 rc
= ngx_mail_pop3_pass(s
, c
);
204 rc
= ngx_mail_pop3_capa(s
, c
, 0);
215 rc
= NGX_MAIL_PARSE_INVALID_COMMAND
;
221 /* suppress warnings */
222 case ngx_pop3_passwd
:
225 case ngx_pop3_auth_login_username
:
226 rc
= ngx_mail_auth_login_username(s
, c
, 0);
228 ngx_str_set(&s
->out
, pop3_password
);
229 s
->mail_state
= ngx_pop3_auth_login_password
;
232 case ngx_pop3_auth_login_password
:
233 rc
= ngx_mail_auth_login_password(s
, c
);
236 case ngx_pop3_auth_plain
:
237 rc
= ngx_mail_auth_plain(s
, c
, 0);
240 case ngx_pop3_auth_cram_md5
:
241 rc
= ngx_mail_auth_cram_md5(s
, c
);
253 ngx_mail_session_internal_server_error(s
);
256 case NGX_MAIL_PARSE_INVALID_COMMAND
:
257 s
->mail_state
= ngx_pop3_start
;
260 ngx_str_set(&s
->out
, pop3_invalid_command
);
267 s
->buffer
->pos
= s
->buffer
->start
;
268 s
->buffer
->last
= s
->buffer
->start
;
271 s
->arg_start
= s
->buffer
->start
;
274 ngx_mail_send(c
->write
);
279 ngx_mail_pop3_user(ngx_mail_session_t
*s
, ngx_connection_t
*c
)
284 if (ngx_mail_starttls_only(s
, c
)) {
285 return NGX_MAIL_PARSE_INVALID_COMMAND
;
289 if (s
->args
.nelts
!= 1) {
290 return NGX_MAIL_PARSE_INVALID_COMMAND
;
294 s
->login
.len
= arg
[0].len
;
295 s
->login
.data
= ngx_pnalloc(c
->pool
, s
->login
.len
);
296 if (s
->login
.data
== NULL
) {
300 ngx_memcpy(s
->login
.data
, arg
[0].data
, s
->login
.len
);
302 ngx_log_debug1(NGX_LOG_DEBUG_MAIL
, c
->log
, 0,
303 "pop3 login: \"%V\"", &s
->login
);
305 s
->mail_state
= ngx_pop3_user
;
312 ngx_mail_pop3_pass(ngx_mail_session_t
*s
, ngx_connection_t
*c
)
316 if (s
->args
.nelts
!= 1) {
317 return NGX_MAIL_PARSE_INVALID_COMMAND
;
321 s
->passwd
.len
= arg
[0].len
;
322 s
->passwd
.data
= ngx_pnalloc(c
->pool
, s
->passwd
.len
);
323 if (s
->passwd
.data
== NULL
) {
327 ngx_memcpy(s
->passwd
.data
, arg
[0].data
, s
->passwd
.len
);
329 #if (NGX_DEBUG_MAIL_PASSWD)
330 ngx_log_debug1(NGX_LOG_DEBUG_MAIL
, c
->log
, 0,
331 "pop3 passwd: \"%V\"", &s
->passwd
);
339 ngx_mail_pop3_capa(ngx_mail_session_t
*s
, ngx_connection_t
*c
, ngx_int_t stls
)
341 ngx_mail_pop3_srv_conf_t
*pscf
;
343 pscf
= ngx_mail_get_module_srv_conf(s
, ngx_mail_pop3_module
);
347 if (stls
&& c
->ssl
== NULL
) {
348 ngx_mail_ssl_conf_t
*sslcf
;
350 sslcf
= ngx_mail_get_module_srv_conf(s
, ngx_mail_ssl_module
);
352 if (sslcf
->starttls
== NGX_MAIL_STARTTLS_ON
) {
353 s
->out
= pscf
->starttls_capability
;
357 if (sslcf
->starttls
== NGX_MAIL_STARTTLS_ONLY
) {
358 s
->out
= pscf
->starttls_only_capability
;
365 s
->out
= pscf
->capability
;
371 ngx_mail_pop3_stls(ngx_mail_session_t
*s
, ngx_connection_t
*c
)
374 ngx_mail_ssl_conf_t
*sslcf
;
376 if (c
->ssl
== NULL
) {
377 sslcf
= ngx_mail_get_module_srv_conf(s
, ngx_mail_ssl_module
);
378 if (sslcf
->starttls
) {
379 c
->read
->handler
= ngx_mail_starttls_handler
;
386 return NGX_MAIL_PARSE_INVALID_COMMAND
;
391 ngx_mail_pop3_apop(ngx_mail_session_t
*s
, ngx_connection_t
*c
)
394 ngx_mail_pop3_srv_conf_t
*pscf
;
397 if (ngx_mail_starttls_only(s
, c
)) {
398 return NGX_MAIL_PARSE_INVALID_COMMAND
;
402 if (s
->args
.nelts
!= 2) {
403 return NGX_MAIL_PARSE_INVALID_COMMAND
;
406 pscf
= ngx_mail_get_module_srv_conf(s
, ngx_mail_pop3_module
);
408 if (!(pscf
->auth_methods
& NGX_MAIL_AUTH_APOP_ENABLED
)) {
409 return NGX_MAIL_PARSE_INVALID_COMMAND
;
414 s
->login
.len
= arg
[0].len
;
415 s
->login
.data
= ngx_pnalloc(c
->pool
, s
->login
.len
);
416 if (s
->login
.data
== NULL
) {
420 ngx_memcpy(s
->login
.data
, arg
[0].data
, s
->login
.len
);
422 s
->passwd
.len
= arg
[1].len
;
423 s
->passwd
.data
= ngx_pnalloc(c
->pool
, s
->passwd
.len
);
424 if (s
->passwd
.data
== NULL
) {
428 ngx_memcpy(s
->passwd
.data
, arg
[1].data
, s
->passwd
.len
);
430 ngx_log_debug2(NGX_LOG_DEBUG_MAIL
, c
->log
, 0,
431 "pop3 apop: \"%V\" \"%V\"", &s
->login
, &s
->passwd
);
433 s
->auth_method
= NGX_MAIL_AUTH_APOP
;
440 ngx_mail_pop3_auth(ngx_mail_session_t
*s
, ngx_connection_t
*c
)
443 ngx_mail_pop3_srv_conf_t
*pscf
;
446 if (ngx_mail_starttls_only(s
, c
)) {
447 return NGX_MAIL_PARSE_INVALID_COMMAND
;
451 pscf
= ngx_mail_get_module_srv_conf(s
, ngx_mail_pop3_module
);
453 if (s
->args
.nelts
== 0) {
454 s
->out
= pscf
->auth_capability
;
460 rc
= ngx_mail_auth_parse(s
, c
);
464 case NGX_MAIL_AUTH_LOGIN
:
466 ngx_str_set(&s
->out
, pop3_username
);
467 s
->mail_state
= ngx_pop3_auth_login_username
;
471 case NGX_MAIL_AUTH_LOGIN_USERNAME
:
473 ngx_str_set(&s
->out
, pop3_password
);
474 s
->mail_state
= ngx_pop3_auth_login_password
;
476 return ngx_mail_auth_login_username(s
, c
, 1);
478 case NGX_MAIL_AUTH_PLAIN
:
480 ngx_str_set(&s
->out
, pop3_next
);
481 s
->mail_state
= ngx_pop3_auth_plain
;
485 case NGX_MAIL_AUTH_CRAM_MD5
:
487 if (!(pscf
->auth_methods
& NGX_MAIL_AUTH_CRAM_MD5_ENABLED
)) {
488 return NGX_MAIL_PARSE_INVALID_COMMAND
;
491 if (ngx_mail_auth_cram_md5_salt(s
, c
, "+ ", 2) == NGX_OK
) {
492 s
->mail_state
= ngx_pop3_auth_cram_md5
;