Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nginx/nginx.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/imap/ngx_imap_proxy_module.c')
-rw-r--r--src/imap/ngx_imap_proxy_module.c296
1 files changed, 240 insertions, 56 deletions
diff --git a/src/imap/ngx_imap_proxy_module.c b/src/imap/ngx_imap_proxy_module.c
index b3bedae58..5177e289f 100644
--- a/src/imap/ngx_imap_proxy_module.c
+++ b/src/imap/ngx_imap_proxy_module.c
@@ -17,16 +17,23 @@ typedef struct {
static void ngx_imap_proxy_block_read(ngx_event_t *rev);
-static void ngx_imap_proxy_auth_handler(ngx_event_t *rev);
+static void ngx_imap_proxy_imap_handler(ngx_event_t *rev);
+static void ngx_imap_proxy_pop3_handler(ngx_event_t *rev);
static void ngx_imap_proxy_dummy_handler(ngx_event_t *ev);
-static ngx_int_t ngx_imap_proxy_read_response(ngx_imap_session_t *s);
+static ngx_int_t ngx_imap_proxy_read_response(ngx_imap_session_t *s,
+ ngx_uint_t what);
static void ngx_imap_proxy_handler(ngx_event_t *ev);
+static void ngx_imap_proxy_internal_server_error(ngx_imap_session_t *s);
static void ngx_imap_proxy_close_session(ngx_imap_session_t *s);
static void *ngx_imap_proxy_create_conf(ngx_conf_t *cf);
static char *ngx_imap_proxy_merge_conf(ngx_conf_t *cf, void *parent,
void *child);
+#define NGX_IMAP_WAIT_OK 0
+#define NGX_IMAP_WAIT_NEXT 1
+
+
static ngx_command_t ngx_imap_proxy_commands[] = {
{ ngx_string("proxy"),
NGX_IMAP_MAIN_CONF|NGX_IMAP_SRV_CONF|NGX_CONF_FLAG,
@@ -61,12 +68,13 @@ ngx_module_t ngx_imap_proxy_module = {
void
ngx_imap_proxy_init(ngx_imap_session_t *s, ngx_peers_t *peers)
{
- ngx_int_t rc;
- ngx_imap_proxy_ctx_t *p;
+ ngx_int_t rc;
+ ngx_imap_proxy_ctx_t *p;
+ ngx_imap_core_srv_conf_t *cscf;
p = ngx_pcalloc(s->connection->pool, sizeof(ngx_imap_proxy_ctx_t));
if (p == NULL) {
- ngx_imap_close_connection(s->connection);
+ ngx_imap_session_internal_server_error(s);
return;
}
@@ -79,16 +87,27 @@ ngx_imap_proxy_init(ngx_imap_session_t *s, ngx_peers_t *peers)
rc = ngx_event_connect_peer(&p->upstream);
if (rc == NGX_ERROR) {
- ngx_imap_proxy_close_session(s);
+ ngx_imap_session_internal_server_error(s);
return;
}
+ cscf = ngx_imap_get_module_srv_conf(s, ngx_imap_core_module);
+ ngx_add_timer(p->upstream.connection->read, cscf->timeout);
+
p->upstream.connection->data = s;
p->upstream.connection->pool = s->connection->pool;
s->connection->read->handler = ngx_imap_proxy_block_read;
- p->upstream.connection->read->handler = ngx_imap_proxy_auth_handler;
p->upstream.connection->write->handler = ngx_imap_proxy_dummy_handler;
+
+ if (s->protocol == NGX_IMAP_POP3_PROTOCOL) {
+ p->upstream.connection->read->handler = ngx_imap_proxy_pop3_handler;
+ s->imap_state = ngx_pop3_start;
+
+ } else {
+ p->upstream.connection->read->handler = ngx_imap_proxy_imap_handler;
+ s->imap_state = ngx_imap_start;
+ }
}
@@ -110,106 +129,242 @@ ngx_imap_proxy_block_read(ngx_event_t *rev)
static void
-ngx_imap_proxy_auth_handler(ngx_event_t *rev)
+ngx_imap_proxy_imap_handler(ngx_event_t *rev)
{
- u_char *p;
- ngx_int_t rc;
- ngx_str_t line;
- ngx_connection_t *c;
- ngx_imap_session_t *s;
+ u_char *p;
+ ngx_int_t rc;
+ ngx_str_t line;
+ ngx_connection_t *c;
+ ngx_imap_session_t *s;
+ ngx_imap_core_srv_conf_t *cscf;
- ngx_log_debug0(NGX_LOG_DEBUG_IMAP, rev->log, 0, "imap proxy auth handler");
+ ngx_log_debug0(NGX_LOG_DEBUG_IMAP, rev->log, 0,
+ "imap proxy imap auth handler");
c = rev->data;
s = c->data;
if (rev->timedout) {
- ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
- ngx_imap_proxy_close_session(s);
+ ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT,
+ "upstream timed out");
+ ngx_imap_proxy_internal_server_error(s);
return;
}
if (s->proxy->buffer == NULL) {
- s->proxy->buffer = ngx_create_temp_buf(c->pool, /* STUB */ 4096);
+ cscf = ngx_imap_get_module_srv_conf(s, ngx_imap_core_module);
+
+ s->proxy->buffer = ngx_create_temp_buf(c->pool,
+ cscf->proxy_buffer_size);
if (s->proxy->buffer == NULL) {
- ngx_imap_proxy_close_session(s);
+ ngx_imap_proxy_internal_server_error(s);
return;
}
}
- rc = ngx_imap_proxy_read_response(s);
+ rc = ngx_imap_proxy_read_response(s, s->imap_state == ngx_imap_start ?
+ NGX_IMAP_WAIT_OK : NGX_IMAP_WAIT_NEXT);
if (rc == NGX_AGAIN) {
return;
}
if (rc == NGX_ERROR) {
- /* TODO: ngx_imap_proxy_finalize_session(s, NGX_IMAP_INTERNAL_ERROR) */
- ngx_imap_proxy_close_session(s);
+ ngx_imap_proxy_internal_server_error(s);
return;
}
- if (s->imap_state == ngx_pop3_start) {
+ switch (s->imap_state) {
+
+ case ngx_imap_start:
+ ngx_log_debug0(NGX_LOG_DEBUG_IMAP, rev->log, 0,
+ "imap proxy send login");
+ line.len = s->tag.len + sizeof("LOGIN ") - 1
+ + 1 + NGX_SIZE_T_LEN + 1 + 2;
+ line.data = ngx_palloc(c->pool, line.len);
+ if (line.data == NULL) {
+ ngx_imap_proxy_internal_server_error(s);
+ return;
+ }
+
+ line.len = ngx_sprintf(line.data, "%VLOGIN {%uz}" CRLF,
+ &s->tag, s->login.len)
+ - line.data;
+
+ s->imap_state = ngx_imap_login;
+ break;
+
+ case ngx_imap_login:
ngx_log_debug0(NGX_LOG_DEBUG_IMAP, rev->log, 0, "imap proxy send user");
- line.len = sizeof("USER ") + s->login.len - 1 + 2;
+ line.len = s->login.len + 1 + NGX_SIZE_T_LEN + 1 + 2;
line.data = ngx_palloc(c->pool, line.len);
if (line.data == NULL) {
- ngx_imap_proxy_close_session(s);
+ ngx_imap_proxy_internal_server_error(s);
return;
}
- p = ngx_cpymem(line.data, "USER ", sizeof("USER ") - 1);
- p = ngx_cpymem(p, s->login.data, s->login.len);
- *p++ = CR; *p = LF;
+ line.len = ngx_sprintf(line.data, "%V{%uz}" CRLF,
+ &s->login, s->passwd.len)
+ - line.data;
+
+ s->imap_state = ngx_imap_user;
+ break;
+
+ case ngx_imap_user:
+ ngx_log_debug0(NGX_LOG_DEBUG_IMAP, rev->log, 0,
+ "imap proxy send passwd");
- if (ngx_send(c, line.data, line.len) < (ssize_t) line.len) {
- /*
- * we treat the incomplete sending as NGX_ERROR
- * because it is very strange here
- */
- ngx_imap_close_connection(c);
+ line.len = s->passwd.len + 2;
+ line.data = ngx_palloc(c->pool, line.len);
+ if (line.data == NULL) {
+ ngx_imap_proxy_internal_server_error(s);
return;
}
- s->imap_state = ngx_pop3_user;
+ p = ngx_cpymem(line.data, s->passwd.data, s->passwd.len);
+ *p++ = CR; *p = LF;
+
+ s->imap_state = ngx_imap_passwd;
+ break;
- s->proxy->buffer->pos = s->proxy->buffer->start;
- s->proxy->buffer->last = s->proxy->buffer->start;
+ default:
+#if (NGX_SUPPRESS_WARN)
+ line.len = 0;
+ line.data = NULL;
+#endif
+ break;
+ }
+ if (ngx_send(c, line.data, line.len) < (ssize_t) line.len) {
+ /*
+ * we treat the incomplete sending as NGX_ERROR
+ * because it is very strange here
+ */
+ ngx_imap_proxy_internal_server_error(s);
return;
}
- ngx_log_debug0(NGX_LOG_DEBUG_IMAP, rev->log, 0, "imap proxy send pass");
+ s->proxy->buffer->pos = s->proxy->buffer->start;
+ s->proxy->buffer->last = s->proxy->buffer->start;
- line.len = sizeof("PASS ") + s->passwd.len - 1 + 2;
- line.data = ngx_palloc(c->pool, line.len);
- if (line.data == NULL) {
- ngx_imap_proxy_close_session(s);
+ if (s->imap_state == ngx_imap_passwd) {
+ s->connection->read->handler = ngx_imap_proxy_handler;
+ s->connection->write->handler = ngx_imap_proxy_handler;
+ rev->handler = ngx_imap_proxy_handler;
+ c->write->handler = ngx_imap_proxy_handler;
+ }
+}
+
+
+static void
+ngx_imap_proxy_pop3_handler(ngx_event_t *rev)
+{
+ u_char *p;
+ ngx_int_t rc;
+ ngx_str_t line;
+ ngx_connection_t *c;
+ ngx_imap_session_t *s;
+ ngx_imap_core_srv_conf_t *cscf;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_IMAP, rev->log, 0,
+ "imap proxy pop3 auth handler");
+
+ c = rev->data;
+ s = c->data;
+
+ if (rev->timedout) {
+ ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT,
+ "upstream timed out");
+ ngx_imap_proxy_internal_server_error(s);
+ return;
+ }
+
+ if (s->proxy->buffer == NULL) {
+ cscf = ngx_imap_get_module_srv_conf(s, ngx_imap_core_module);
+
+ s->proxy->buffer = ngx_create_temp_buf(c->pool,
+ cscf->proxy_buffer_size);
+ if (s->proxy->buffer == NULL) {
+ ngx_imap_proxy_internal_server_error(s);
+ return;
+ }
+ }
+
+ rc = ngx_imap_proxy_read_response(s, NGX_IMAP_WAIT_OK);
+
+ if (rc == NGX_AGAIN) {
return;
}
- p = ngx_cpymem(line.data, "PASS ", sizeof("PASS ") - 1);
- p = ngx_cpymem(p, s->passwd.data, s->passwd.len);
- *p++ = CR; *p = LF;
+ if (rc == NGX_ERROR) {
+ ngx_imap_proxy_internal_server_error(s);
+ return;
+ }
+
+ switch (s->imap_state) {
+
+ case ngx_pop3_start:
+ ngx_log_debug0(NGX_LOG_DEBUG_IMAP, rev->log, 0, "imap proxy send user");
+
+ line.len = sizeof("USER ") - 1 + s->login.len + 2;
+ line.data = ngx_palloc(c->pool, line.len);
+ if (line.data == NULL) {
+ ngx_imap_proxy_internal_server_error(s);
+ return;
+ }
+
+ p = ngx_cpymem(line.data, "USER ", sizeof("USER ") - 1);
+ p = ngx_cpymem(p, s->login.data, s->login.len);
+ *p++ = CR; *p = LF;
+
+ s->imap_state = ngx_pop3_user;
+ break;
+
+ case ngx_pop3_user:
+ ngx_log_debug0(NGX_LOG_DEBUG_IMAP, rev->log, 0, "imap proxy send pass");
+
+ line.len = sizeof("PASS ") - 1 + s->passwd.len + 2;
+ line.data = ngx_palloc(c->pool, line.len);
+ if (line.data == NULL) {
+ ngx_imap_proxy_internal_server_error(s);
+ return;
+ }
+
+ p = ngx_cpymem(line.data, "PASS ", sizeof("PASS ") - 1);
+ p = ngx_cpymem(p, s->passwd.data, s->passwd.len);
+ *p++ = CR; *p = LF;
+
+ s->imap_state = ngx_pop3_passwd;
+ break;
+
+ default:
+#if (NGX_SUPPRESS_WARN)
+ line.len = 0;
+ line.data = NULL;
+#endif
+ break;
+ }
if (ngx_send(c, line.data, line.len) < (ssize_t) line.len) {
/*
* we treat the incomplete sending as NGX_ERROR
* because it is very strange here
*/
- ngx_imap_close_connection(c);
+ ngx_imap_proxy_internal_server_error(s);
return;
}
s->proxy->buffer->pos = s->proxy->buffer->start;
s->proxy->buffer->last = s->proxy->buffer->start;
- s->connection->read->handler = ngx_imap_proxy_handler;
- s->connection->write->handler = ngx_imap_proxy_handler;
- rev->handler = ngx_imap_proxy_handler;
- c->write->handler = ngx_imap_proxy_handler;
+ if (s->imap_state == ngx_pop3_passwd) {
+ s->connection->read->handler = ngx_imap_proxy_handler;
+ s->connection->write->handler = ngx_imap_proxy_handler;
+ rev->handler = ngx_imap_proxy_handler;
+ c->write->handler = ngx_imap_proxy_handler;
+ }
}
@@ -221,7 +376,7 @@ ngx_imap_proxy_dummy_handler(ngx_event_t *ev)
static ngx_int_t
-ngx_imap_proxy_read_response(ngx_imap_session_t *s)
+ngx_imap_proxy_read_response(ngx_imap_session_t *s, ngx_uint_t what)
{
u_char *p;
ssize_t n;
@@ -259,17 +414,31 @@ ngx_imap_proxy_read_response(ngx_imap_session_t *s)
p = b->pos;
- if (p[0] == '+' && p[1] == 'O' && p[2] == 'K') {
- return NGX_OK;
- }
+ if (s->protocol == NGX_IMAP_POP3_PROTOCOL) {
+ if (p[0] == '+' && p[1] == 'O' && p[2] == 'K') {
+ return NGX_OK;
+ }
- if (p[0] == '-' && p[1] == 'E' && p[2] == 'R' && p[3] == 'R') {
- return NGX_IMAP_PROXY_ERROR;
+ if (p[0] == '-' && p[1] == 'E' && p[2] == 'R' && p[3] == 'R') {
+ return NGX_IMAP_PROXY_ERROR;
+ }
+
+ } else {
+ if (what == NGX_IMAP_WAIT_OK) {
+ if (p[0] == '*' && p[1] == ' ' && p[2] == 'O' && p[3] == 'K') {
+ return NGX_OK;
+ }
+
+ } else {
+ if (p[0] == '+' && p[1] == ' ' && p[2] == 'O' && p[3] == 'K') {
+ return NGX_OK;
+ }
+ }
}
*(b->last - 2) = '\0';
ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
- "upstream sent invalid greeting line: \"%s\"", p);
+ "upstream sent invalid response: \"%s\"", p);
return NGX_IMAP_PROXY_INVALID;
}
@@ -397,6 +566,21 @@ ngx_imap_proxy_handler(ngx_event_t *ev)
static void
+ngx_imap_proxy_internal_server_error(ngx_imap_session_t *s)
+{
+ if (s->proxy->upstream.connection) {
+ ngx_log_debug1(NGX_LOG_DEBUG_IMAP, s->connection->log, 0,
+ "close imap proxy connection: %d",
+ s->proxy->upstream.connection->fd);
+
+ ngx_close_connection(s->proxy->upstream.connection);
+ }
+
+ ngx_imap_session_internal_server_error(s);
+}
+
+
+static void
ngx_imap_proxy_close_session(ngx_imap_session_t *s)
{
if (s->proxy->upstream.connection) {