1e18a033bSKonstantin Ananyev
2e18a033bSKonstantin Ananyev/*
3e18a033bSKonstantin Ananyev * Copyright (C) Igor Sysoev
4e18a033bSKonstantin Ananyev * Copyright (C) Nginx, Inc.
5e18a033bSKonstantin Ananyev */
6e18a033bSKonstantin Ananyev
7e18a033bSKonstantin Ananyev
8e18a033bSKonstantin Ananyev#include <ngx_config.h>
9e18a033bSKonstantin Ananyev#include <ngx_core.h>
10e18a033bSKonstantin Ananyev#include <ngx_event.h>
11e18a033bSKonstantin Ananyev#include <ngx_event_connect.h>
12e18a033bSKonstantin Ananyev#include <ngx_mail.h>
13e18a033bSKonstantin Ananyev
14e18a033bSKonstantin Ananyev
15e18a033bSKonstantin Ananyevtypedef struct {
16e18a033bSKonstantin Ananyev    ngx_flag_t  enable;
17e18a033bSKonstantin Ananyev    ngx_flag_t  pass_error_message;
18e18a033bSKonstantin Ananyev    ngx_flag_t  xclient;
19e18a033bSKonstantin Ananyev    size_t      buffer_size;
20e18a033bSKonstantin Ananyev    ngx_msec_t  timeout;
21e18a033bSKonstantin Ananyev} ngx_mail_proxy_conf_t;
22e18a033bSKonstantin Ananyev
23e18a033bSKonstantin Ananyev
24e18a033bSKonstantin Ananyevstatic void ngx_mail_proxy_block_read(ngx_event_t *rev);
25e18a033bSKonstantin Ananyevstatic void ngx_mail_proxy_pop3_handler(ngx_event_t *rev);
26e18a033bSKonstantin Ananyevstatic void ngx_mail_proxy_imap_handler(ngx_event_t *rev);
27e18a033bSKonstantin Ananyevstatic void ngx_mail_proxy_smtp_handler(ngx_event_t *rev);
28e18a033bSKonstantin Ananyevstatic void ngx_mail_proxy_dummy_handler(ngx_event_t *ev);
29e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_mail_proxy_read_response(ngx_mail_session_t *s,
30e18a033bSKonstantin Ananyev    ngx_uint_t state);
31e18a033bSKonstantin Ananyevstatic void ngx_mail_proxy_handler(ngx_event_t *ev);
32e18a033bSKonstantin Ananyevstatic void ngx_mail_proxy_upstream_error(ngx_mail_session_t *s);
33e18a033bSKonstantin Ananyevstatic void ngx_mail_proxy_internal_server_error(ngx_mail_session_t *s);
34e18a033bSKonstantin Ananyevstatic void ngx_mail_proxy_close_session(ngx_mail_session_t *s);
35e18a033bSKonstantin Ananyevstatic void *ngx_mail_proxy_create_conf(ngx_conf_t *cf);
36e18a033bSKonstantin Ananyevstatic char *ngx_mail_proxy_merge_conf(ngx_conf_t *cf, void *parent,
37e18a033bSKonstantin Ananyev    void *child);
38e18a033bSKonstantin Ananyev
39e18a033bSKonstantin Ananyev
40e18a033bSKonstantin Ananyevstatic ngx_command_t  ngx_mail_proxy_commands[] = {
41e18a033bSKonstantin Ananyev
42e18a033bSKonstantin Ananyev    { ngx_string("proxy"),
43e18a033bSKonstantin Ananyev      NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG,
44e18a033bSKonstantin Ananyev      ngx_conf_set_flag_slot,
45e18a033bSKonstantin Ananyev      NGX_MAIL_SRV_CONF_OFFSET,
46e18a033bSKonstantin Ananyev      offsetof(ngx_mail_proxy_conf_t, enable),
47e18a033bSKonstantin Ananyev      NULL },
48e18a033bSKonstantin Ananyev
49e18a033bSKonstantin Ananyev    { ngx_string("proxy_buffer"),
50e18a033bSKonstantin Ananyev      NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
51e18a033bSKonstantin Ananyev      ngx_conf_set_size_slot,
52e18a033bSKonstantin Ananyev      NGX_MAIL_SRV_CONF_OFFSET,
53e18a033bSKonstantin Ananyev      offsetof(ngx_mail_proxy_conf_t, buffer_size),
54e18a033bSKonstantin Ananyev      NULL },
55e18a033bSKonstantin Ananyev
56e18a033bSKonstantin Ananyev    { ngx_string("proxy_timeout"),
57e18a033bSKonstantin Ananyev      NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
58e18a033bSKonstantin Ananyev      ngx_conf_set_msec_slot,
59e18a033bSKonstantin Ananyev      NGX_MAIL_SRV_CONF_OFFSET,
60e18a033bSKonstantin Ananyev      offsetof(ngx_mail_proxy_conf_t, timeout),
61e18a033bSKonstantin Ananyev      NULL },
62e18a033bSKonstantin Ananyev
63e18a033bSKonstantin Ananyev    { ngx_string("proxy_pass_error_message"),
64e18a033bSKonstantin Ananyev      NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG,
65e18a033bSKonstantin Ananyev      ngx_conf_set_flag_slot,
66e18a033bSKonstantin Ananyev      NGX_MAIL_SRV_CONF_OFFSET,
67e18a033bSKonstantin Ananyev      offsetof(ngx_mail_proxy_conf_t, pass_error_message),
68e18a033bSKonstantin Ananyev      NULL },
69e18a033bSKonstantin Ananyev
70e18a033bSKonstantin Ananyev    { ngx_string("xclient"),
71e18a033bSKonstantin Ananyev      NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG,
72e18a033bSKonstantin Ananyev      ngx_conf_set_flag_slot,
73e18a033bSKonstantin Ananyev      NGX_MAIL_SRV_CONF_OFFSET,
74e18a033bSKonstantin Ananyev      offsetof(ngx_mail_proxy_conf_t, xclient),
75e18a033bSKonstantin Ananyev      NULL },
76e18a033bSKonstantin Ananyev
77e18a033bSKonstantin Ananyev      ngx_null_command
78e18a033bSKonstantin Ananyev};
79e18a033bSKonstantin Ananyev
80e18a033bSKonstantin Ananyev
81e18a033bSKonstantin Ananyevstatic ngx_mail_module_t  ngx_mail_proxy_module_ctx = {
82e18a033bSKonstantin Ananyev    NULL,                                  /* protocol */
83e18a033bSKonstantin Ananyev
84e18a033bSKonstantin Ananyev    NULL,                                  /* create main configuration */
85e18a033bSKonstantin Ananyev    NULL,                                  /* init main configuration */
86e18a033bSKonstantin Ananyev
87e18a033bSKonstantin Ananyev    ngx_mail_proxy_create_conf,            /* create server configuration */
88e18a033bSKonstantin Ananyev    ngx_mail_proxy_merge_conf              /* merge server configuration */
89e18a033bSKonstantin Ananyev};
90e18a033bSKonstantin Ananyev
91e18a033bSKonstantin Ananyev
92e18a033bSKonstantin Ananyevngx_module_t  ngx_mail_proxy_module = {
93e18a033bSKonstantin Ananyev    NGX_MODULE_V1,
94e18a033bSKonstantin Ananyev    &ngx_mail_proxy_module_ctx,            /* module context */
95e18a033bSKonstantin Ananyev    ngx_mail_proxy_commands,               /* module directives */
96e18a033bSKonstantin Ananyev    NGX_MAIL_MODULE,                       /* module type */
97e18a033bSKonstantin Ananyev    NULL,                                  /* init master */
98e18a033bSKonstantin Ananyev    NULL,                                  /* init module */
99e18a033bSKonstantin Ananyev    NULL,                                  /* init process */
100e18a033bSKonstantin Ananyev    NULL,                                  /* init thread */
101e18a033bSKonstantin Ananyev    NULL,                                  /* exit thread */
102e18a033bSKonstantin Ananyev    NULL,                                  /* exit process */
103e18a033bSKonstantin Ananyev    NULL,                                  /* exit master */
104e18a033bSKonstantin Ananyev    NGX_MODULE_V1_PADDING
105e18a033bSKonstantin Ananyev};
106e18a033bSKonstantin Ananyev
107e18a033bSKonstantin Ananyev
108e18a033bSKonstantin Ananyevstatic u_char  smtp_auth_ok[] = "235 2.0.0 OK" CRLF;
109e18a033bSKonstantin Ananyev
110e18a033bSKonstantin Ananyev
111e18a033bSKonstantin Ananyevvoid
112e18a033bSKonstantin Ananyevngx_mail_proxy_init(ngx_mail_session_t *s, ngx_addr_t *peer)
113e18a033bSKonstantin Ananyev{
114e18a033bSKonstantin Ananyev    ngx_int_t                  rc;
115e18a033bSKonstantin Ananyev    ngx_mail_proxy_ctx_t      *p;
116e18a033bSKonstantin Ananyev    ngx_mail_proxy_conf_t     *pcf;
117e18a033bSKonstantin Ananyev    ngx_mail_core_srv_conf_t  *cscf;
118e18a033bSKonstantin Ananyev
119e18a033bSKonstantin Ananyev    s->connection->log->action = "connecting to upstream";
120e18a033bSKonstantin Ananyev
121e18a033bSKonstantin Ananyev    cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
122e18a033bSKonstantin Ananyev
123e18a033bSKonstantin Ananyev    p = ngx_pcalloc(s->connection->pool, sizeof(ngx_mail_proxy_ctx_t));
124e18a033bSKonstantin Ananyev    if (p == NULL) {
125e18a033bSKonstantin Ananyev        ngx_mail_session_internal_server_error(s);
126e18a033bSKonstantin Ananyev        return;
127e18a033bSKonstantin Ananyev    }
128e18a033bSKonstantin Ananyev
129e18a033bSKonstantin Ananyev    s->proxy = p;
130e18a033bSKonstantin Ananyev
131e18a033bSKonstantin Ananyev    p->upstream.sockaddr = peer->sockaddr;
132e18a033bSKonstantin Ananyev    p->upstream.socklen = peer->socklen;
133e18a033bSKonstantin Ananyev    p->upstream.name = &peer->name;
134e18a033bSKonstantin Ananyev    p->upstream.get = ngx_event_get_peer;
135e18a033bSKonstantin Ananyev    p->upstream.log = s->connection->log;
136e18a033bSKonstantin Ananyev    p->upstream.log_error = NGX_ERROR_ERR;
137e18a033bSKonstantin Ananyev
138e18a033bSKonstantin Ananyev    rc = ngx_event_connect_peer(&p->upstream);
139e18a033bSKonstantin Ananyev
140e18a033bSKonstantin Ananyev    if (rc == NGX_ERROR || rc == NGX_BUSY || rc == NGX_DECLINED) {
141e18a033bSKonstantin Ananyev        ngx_mail_proxy_internal_server_error(s);
142e18a033bSKonstantin Ananyev        return;
143e18a033bSKonstantin Ananyev    }
144e18a033bSKonstantin Ananyev
145e18a033bSKonstantin Ananyev    ngx_add_timer(p->upstream.connection->read, cscf->timeout);
146e18a033bSKonstantin Ananyev
147e18a033bSKonstantin Ananyev    p->upstream.connection->data = s;
148e18a033bSKonstantin Ananyev    p->upstream.connection->pool = s->connection->pool;
149e18a033bSKonstantin Ananyev
150e18a033bSKonstantin Ananyev    s->connection->read->handler = ngx_mail_proxy_block_read;
151e18a033bSKonstantin Ananyev    p->upstream.connection->write->handler = ngx_mail_proxy_dummy_handler;
152e18a033bSKonstantin Ananyev
153e18a033bSKonstantin Ananyev    pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module);
154e18a033bSKonstantin Ananyev
155e18a033bSKonstantin Ananyev    s->proxy->buffer = ngx_create_temp_buf(s->connection->pool,
156e18a033bSKonstantin Ananyev                                           pcf->buffer_size);
157e18a033bSKonstantin Ananyev    if (s->proxy->buffer == NULL) {
158e18a033bSKonstantin Ananyev        ngx_mail_proxy_internal_server_error(s);
159e18a033bSKonstantin Ananyev        return;
160e18a033bSKonstantin Ananyev    }
161e18a033bSKonstantin Ananyev
162e18a033bSKonstantin Ananyev    s->out.len = 0;
163e18a033bSKonstantin Ananyev
164e18a033bSKonstantin Ananyev    switch (s->protocol) {
165e18a033bSKonstantin Ananyev
166e18a033bSKonstantin Ananyev    case NGX_MAIL_POP3_PROTOCOL:
167e18a033bSKonstantin Ananyev        p->upstream.connection->read->handler = ngx_mail_proxy_pop3_handler;
168e18a033bSKonstantin Ananyev        s->mail_state = ngx_pop3_start;
169e18a033bSKonstantin Ananyev        break;
170e18a033bSKonstantin Ananyev
171e18a033bSKonstantin Ananyev    case NGX_MAIL_IMAP_PROTOCOL:
172e18a033bSKonstantin Ananyev        p->upstream.connection->read->handler = ngx_mail_proxy_imap_handler;
173e18a033bSKonstantin Ananyev        s->mail_state = ngx_imap_start;
174e18a033bSKonstantin Ananyev        break;
175e18a033bSKonstantin Ananyev
176e18a033bSKonstantin Ananyev    default: /* NGX_MAIL_SMTP_PROTOCOL */
177e18a033bSKonstantin Ananyev        p->upstream.connection->read->handler = ngx_mail_proxy_smtp_handler;
178e18a033bSKonstantin Ananyev        s->mail_state = ngx_smtp_start;
179e18a033bSKonstantin Ananyev        break;
180e18a033bSKonstantin Ananyev    }
181e18a033bSKonstantin Ananyev}
182e18a033bSKonstantin Ananyev
183e18a033bSKonstantin Ananyev
184e18a033bSKonstantin Ananyevstatic void
185e18a033bSKonstantin Ananyevngx_mail_proxy_block_read(ngx_event_t *rev)
186e18a033bSKonstantin Ananyev{
187e18a033bSKonstantin Ananyev    ngx_connection_t    *c;
188e18a033bSKonstantin Ananyev    ngx_mail_session_t  *s;
189e18a033bSKonstantin Ananyev
190e18a033bSKonstantin Ananyev    ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0, "mail proxy block read");
191e18a033bSKonstantin Ananyev
192e18a033bSKonstantin Ananyev    if (ngx_handle_read_event(rev, 0) != NGX_OK) {
193e18a033bSKonstantin Ananyev        c = rev->data;
194e18a033bSKonstantin Ananyev        s = c->data;
195e18a033bSKonstantin Ananyev
196e18a033bSKonstantin Ananyev        ngx_mail_proxy_close_session(s);
197e18a033bSKonstantin Ananyev    }
198e18a033bSKonstantin Ananyev}
199e18a033bSKonstantin Ananyev
200e18a033bSKonstantin Ananyev
201e18a033bSKonstantin Ananyevstatic void
202e18a033bSKonstantin Ananyevngx_mail_proxy_pop3_handler(ngx_event_t *rev)
203e18a033bSKonstantin Ananyev{
204e18a033bSKonstantin Ananyev    u_char                 *p;
205e18a033bSKonstantin Ananyev    ngx_int_t               rc;
206e18a033bSKonstantin Ananyev    ngx_str_t               line;
207e18a033bSKonstantin Ananyev    ngx_connection_t       *c;
208e18a033bSKonstantin Ananyev    ngx_mail_session_t     *s;
209e18a033bSKonstantin Ananyev    ngx_mail_proxy_conf_t  *pcf;
210e18a033bSKonstantin Ananyev
211e18a033bSKonstantin Ananyev    ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0,
212e18a033bSKonstantin Ananyev                   "mail proxy pop3 auth handler");
213e18a033bSKonstantin Ananyev
214e18a033bSKonstantin Ananyev    c = rev->data;
215e18a033bSKonstantin Ananyev    s = c->data;
216e18a033bSKonstantin Ananyev
217e18a033bSKonstantin Ananyev    if (rev->timedout) {
218e18a033bSKonstantin Ananyev        ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT,
219e18a033bSKonstantin Ananyev                      "upstream timed out");
220e18a033bSKonstantin Ananyev        c->timedout = 1;
221e18a033bSKonstantin Ananyev        ngx_mail_proxy_internal_server_error(s);
222e18a033bSKonstantin Ananyev        return;
223e18a033bSKonstantin Ananyev    }
224e18a033bSKonstantin Ananyev
225e18a033bSKonstantin Ananyev    rc = ngx_mail_proxy_read_response(s, 0);
226e18a033bSKonstantin Ananyev
227e18a033bSKonstantin Ananyev    if (rc == NGX_AGAIN) {
228e18a033bSKonstantin Ananyev        return;
229e18a033bSKonstantin Ananyev    }
230e18a033bSKonstantin Ananyev
231e18a033bSKonstantin Ananyev    if (rc == NGX_ERROR) {
232e18a033bSKonstantin Ananyev        ngx_mail_proxy_upstream_error(s);
233e18a033bSKonstantin Ananyev        return;
234e18a033bSKonstantin Ananyev    }
235e18a033bSKonstantin Ananyev
236e18a033bSKonstantin Ananyev    switch (s->mail_state) {
237e18a033bSKonstantin Ananyev
238e18a033bSKonstantin Ananyev    case ngx_pop3_start:
239e18a033bSKonstantin Ananyev        ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0, "mail proxy send user");
240e18a033bSKonstantin Ananyev
241e18a033bSKonstantin Ananyev        s->connection->log->action = "sending user name to upstream";
242e18a033bSKonstantin Ananyev
243e18a033bSKonstantin Ananyev        line.len = sizeof("USER ")  - 1 + s->login.len + 2;
244e18a033bSKonstantin Ananyev        line.data = ngx_pnalloc(c->pool, line.len);
245e18a033bSKonstantin Ananyev        if (line.data == NULL) {
246e18a033bSKonstantin Ananyev            ngx_mail_proxy_internal_server_error(s);
247e18a033bSKonstantin Ananyev            return;
248e18a033bSKonstantin Ananyev        }
249e18a033bSKonstantin Ananyev
250e18a033bSKonstantin Ananyev        p = ngx_cpymem(line.data, "USER ", sizeof("USER ") - 1);
251e18a033bSKonstantin Ananyev        p = ngx_cpymem(p, s->login.data, s->login.len);
252e18a033bSKonstantin Ananyev        *p++ = CR; *p = LF;
253e18a033bSKonstantin Ananyev
254e18a033bSKonstantin Ananyev        s->mail_state = ngx_pop3_user;
255e18a033bSKonstantin Ananyev        break;
256e18a033bSKonstantin Ananyev
257e18a033bSKonstantin Ananyev    case ngx_pop3_user:
258e18a033bSKonstantin Ananyev        ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0, "mail proxy send pass");
259e18a033bSKonstantin Ananyev
260e18a033bSKonstantin Ananyev        s->connection->log->action = "sending password to upstream";
261e18a033bSKonstantin Ananyev
262e18a033bSKonstantin Ananyev        line.len = sizeof("PASS ")  - 1 + s->passwd.len + 2;
263e18a033bSKonstantin Ananyev        line.data = ngx_pnalloc(c->pool, line.len);
264e18a033bSKonstantin Ananyev        if (line.data == NULL) {
265e18a033bSKonstantin Ananyev            ngx_mail_proxy_internal_server_error(s);
266e18a033bSKonstantin Ananyev            return;
267e18a033bSKonstantin Ananyev        }
268e18a033bSKonstantin Ananyev
269e18a033bSKonstantin Ananyev        p = ngx_cpymem(line.data, "PASS ", sizeof("PASS ") - 1);
270e18a033bSKonstantin Ananyev        p = ngx_cpymem(p, s->passwd.data, s->passwd.len);
271e18a033bSKonstantin Ananyev        *p++ = CR; *p = LF;
272e18a033bSKonstantin Ananyev
273e18a033bSKonstantin Ananyev        s->mail_state = ngx_pop3_passwd;
274e18a033bSKonstantin Ananyev        break;
275e18a033bSKonstantin Ananyev
276e18a033bSKonstantin Ananyev    case ngx_pop3_passwd:
277e18a033bSKonstantin Ananyev        s->connection->read->handler = ngx_mail_proxy_handler;
278e18a033bSKonstantin Ananyev        s->connection->write->handler = ngx_mail_proxy_handler;
279e18a033bSKonstantin Ananyev        rev->handler = ngx_mail_proxy_handler;
280e18a033bSKonstantin Ananyev        c->write->handler = ngx_mail_proxy_handler;
281e18a033bSKonstantin Ananyev
282e18a033bSKonstantin Ananyev        pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module);
283e18a033bSKonstantin Ananyev        ngx_add_timer(s->connection->read, pcf->timeout);
284e18a033bSKonstantin Ananyev        ngx_del_timer(c->read);
285e18a033bSKonstantin Ananyev
286e18a033bSKonstantin Ananyev        c->log->action = NULL;
287e18a033bSKonstantin Ananyev        ngx_log_error(NGX_LOG_INFO, c->log, 0, "client logged in");
288e18a033bSKonstantin Ananyev
289e18a033bSKonstantin Ananyev        ngx_mail_proxy_handler(s->connection->write);
290e18a033bSKonstantin Ananyev
291e18a033bSKonstantin Ananyev        return;
292e18a033bSKonstantin Ananyev
293e18a033bSKonstantin Ananyev    default:
294e18a033bSKonstantin Ananyev#if (NGX_SUPPRESS_WARN)
295e18a033bSKonstantin Ananyev        ngx_str_null(&line);
296e18a033bSKonstantin Ananyev#endif
297e18a033bSKonstantin Ananyev        break;
298e18a033bSKonstantin Ananyev    }
299e18a033bSKonstantin Ananyev
300e18a033bSKonstantin Ananyev    if (c->send(c, line.data, line.len) < (ssize_t) line.len) {
301e18a033bSKonstantin Ananyev        /*
302e18a033bSKonstantin Ananyev         * we treat the incomplete sending as NGX_ERROR
303e18a033bSKonstantin Ananyev         * because it is very strange here
304e18a033bSKonstantin Ananyev         */
305e18a033bSKonstantin Ananyev        ngx_mail_proxy_internal_server_error(s);
306e18a033bSKonstantin Ananyev        return;
307e18a033bSKonstantin Ananyev    }
308e18a033bSKonstantin Ananyev
309e18a033bSKonstantin Ananyev    s->proxy->buffer->pos = s->proxy->buffer->start;
310e18a033bSKonstantin Ananyev    s->proxy->buffer->last = s->proxy->buffer->start;
311e18a033bSKonstantin Ananyev}
312e18a033bSKonstantin Ananyev
313e18a033bSKonstantin Ananyev
314e18a033bSKonstantin Ananyevstatic void
315e18a033bSKonstantin Ananyevngx_mail_proxy_imap_handler(ngx_event_t *rev)
316e18a033bSKonstantin Ananyev{
317e18a033bSKonstantin Ananyev    u_char                 *p;
318e18a033bSKonstantin Ananyev    ngx_int_t               rc;
319e18a033bSKonstantin Ananyev    ngx_str_t               line;
320e18a033bSKonstantin Ananyev    ngx_connection_t       *c;
321e18a033bSKonstantin Ananyev    ngx_mail_session_t     *s;
322e18a033bSKonstantin Ananyev    ngx_mail_proxy_conf_t  *pcf;
323e18a033bSKonstantin Ananyev
324e18a033bSKonstantin Ananyev    ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0,
325e18a033bSKonstantin Ananyev                   "mail proxy imap auth handler");
326e18a033bSKonstantin Ananyev
327e18a033bSKonstantin Ananyev    c = rev->data;
328e18a033bSKonstantin Ananyev    s = c->data;
329e18a033bSKonstantin Ananyev
330e18a033bSKonstantin Ananyev    if (rev->timedout) {
331e18a033bSKonstantin Ananyev        ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT,
332e18a033bSKonstantin Ananyev                      "upstream timed out");
333e18a033bSKonstantin Ananyev        c->timedout = 1;
334e18a033bSKonstantin Ananyev        ngx_mail_proxy_internal_server_error(s);
335e18a033bSKonstantin Ananyev        return;
336e18a033bSKonstantin Ananyev    }
337e18a033bSKonstantin Ananyev
338e18a033bSKonstantin Ananyev    rc = ngx_mail_proxy_read_response(s, s->mail_state);
339e18a033bSKonstantin Ananyev
340e18a033bSKonstantin Ananyev    if (rc == NGX_AGAIN) {
341e18a033bSKonstantin Ananyev        return;
342e18a033bSKonstantin Ananyev    }
343e18a033bSKonstantin Ananyev
344e18a033bSKonstantin Ananyev    if (rc == NGX_ERROR) {
345e18a033bSKonstantin Ananyev        ngx_mail_proxy_upstream_error(s);
346e18a033bSKonstantin Ananyev        return;
347e18a033bSKonstantin Ananyev    }
348e18a033bSKonstantin Ananyev
349e18a033bSKonstantin Ananyev    switch (s->mail_state) {
350e18a033bSKonstantin Ananyev
351e18a033bSKonstantin Ananyev    case ngx_imap_start:
352e18a033bSKonstantin Ananyev        ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0,
353e18a033bSKonstantin Ananyev                       "mail proxy send login");
354e18a033bSKonstantin Ananyev
355e18a033bSKonstantin Ananyev        s->connection->log->action = "sending LOGIN command to upstream";
356e18a033bSKonstantin Ananyev
357e18a033bSKonstantin Ananyev        line.len = s->tag.len + sizeof("LOGIN ") - 1
358e18a033bSKonstantin Ananyev                   + 1 + NGX_SIZE_T_LEN + 1 + 2;
359e18a033bSKonstantin Ananyev        line.data = ngx_pnalloc(c->pool, line.len);
360e18a033bSKonstantin Ananyev        if (line.data == NULL) {
361e18a033bSKonstantin Ananyev            ngx_mail_proxy_internal_server_error(s);
362e18a033bSKonstantin Ananyev            return;
363e18a033bSKonstantin Ananyev        }
364e18a033bSKonstantin Ananyev
365e18a033bSKonstantin Ananyev        line.len = ngx_sprintf(line.data, "%VLOGIN {%uz}" CRLF,
366e18a033bSKonstantin Ananyev                               &s->tag, s->login.len)
367e18a033bSKonstantin Ananyev                   - line.data;
368e18a033bSKonstantin Ananyev
369e18a033bSKonstantin Ananyev        s->mail_state = ngx_imap_login;
370e18a033bSKonstantin Ananyev        break;
371e18a033bSKonstantin Ananyev
372e18a033bSKonstantin Ananyev    case ngx_imap_login:
373e18a033bSKonstantin Ananyev        ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0, "mail proxy send user");
374e18a033bSKonstantin Ananyev
375e18a033bSKonstantin Ananyev        s->connection->log->action = "sending user name to upstream";
376e18a033bSKonstantin Ananyev
377e18a033bSKonstantin Ananyev        line.len = s->login.len + 1 + 1 + NGX_SIZE_T_LEN + 1 + 2;
378e18a033bSKonstantin Ananyev        line.data = ngx_pnalloc(c->pool, line.len);
379e18a033bSKonstantin Ananyev        if (line.data == NULL) {
380e18a033bSKonstantin Ananyev            ngx_mail_proxy_internal_server_error(s);
381e18a033bSKonstantin Ananyev            return;
382e18a033bSKonstantin Ananyev        }
383e18a033bSKonstantin Ananyev
384e18a033bSKonstantin Ananyev        line.len = ngx_sprintf(line.data, "%V {%uz}" CRLF,
385e18a033bSKonstantin Ananyev                               &s->login, s->passwd.len)
386e18a033bSKonstantin Ananyev                   - line.data;
387e18a033bSKonstantin Ananyev
388e18a033bSKonstantin Ananyev        s->mail_state = ngx_imap_user;
389e18a033bSKonstantin Ananyev        break;
390e18a033bSKonstantin Ananyev
391e18a033bSKonstantin Ananyev    case ngx_imap_user:
392e18a033bSKonstantin Ananyev        ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0,
393e18a033bSKonstantin Ananyev                       "mail proxy send passwd");
394e18a033bSKonstantin Ananyev
395e18a033bSKonstantin Ananyev        s->connection->log->action = "sending password to upstream";
396e18a033bSKonstantin Ananyev
397e18a033bSKonstantin Ananyev        line.len = s->passwd.len + 2;
398e18a033bSKonstantin Ananyev        line.data = ngx_pnalloc(c->pool, line.len);
399e18a033bSKonstantin Ananyev        if (line.data == NULL) {
400e18a033bSKonstantin Ananyev            ngx_mail_proxy_internal_server_error(s);
401e18a033bSKonstantin Ananyev            return;
402e18a033bSKonstantin Ananyev        }
403e18a033bSKonstantin Ananyev
404e18a033bSKonstantin Ananyev        p = ngx_cpymem(line.data, s->passwd.data, s->passwd.len);
405e18a033bSKonstantin Ananyev        *p++ = CR; *p = LF;
406e18a033bSKonstantin Ananyev
407e18a033bSKonstantin Ananyev        s->mail_state = ngx_imap_passwd;
408e18a033bSKonstantin Ananyev        break;
409e18a033bSKonstantin Ananyev
410e18a033bSKonstantin Ananyev    case ngx_imap_passwd:
411e18a033bSKonstantin Ananyev        s->connection->read->handler = ngx_mail_proxy_handler;
412e18a033bSKonstantin Ananyev        s->connection->write->handler = ngx_mail_proxy_handler;
413e18a033bSKonstantin Ananyev        rev->handler = ngx_mail_proxy_handler;
414e18a033bSKonstantin Ananyev        c->write->handler = ngx_mail_proxy_handler;
415e18a033bSKonstantin Ananyev
416