blob: ddff96a29ed6e107893e8a976540afb20d9d4a39 [file] [log] [blame]
Igor Sysoev9e511812004-08-31 19:05:39 +00001
Igor Sysoevd90282d2004-09-28 08:34:51 +00002/*
Igor Sysoevff8da912004-09-29 16:00:49 +00003 * Copyright (C) Igor Sysoev
Igor Sysoevd90282d2004-09-28 08:34:51 +00004 */
5
6
Igor Sysoev9e511812004-08-31 19:05:39 +00007#include <ngx_config.h>
8#include <ngx_core.h>
9#include <ngx_event.h>
Igor Sysoev59cf56c2004-09-07 15:29:22 +000010#include <ngx_imap.h>
Igor Sysoev59cf56c2004-09-07 15:29:22 +000011
12
Igor Sysoev9fa5a822005-09-30 14:41:25 +000013static void ngx_imap_init_session(ngx_connection_t *c);
Igor Sysoeve5733802005-09-08 14:36:09 +000014static void ngx_imap_init_protocol(ngx_event_t *rev);
Igor Sysoev5192b362005-07-08 14:34:20 +000015static ngx_int_t ngx_imap_read_command(ngx_imap_session_t *s);
Igor Sysoeve5733802005-09-08 14:36:09 +000016static u_char *ngx_imap_log_error(ngx_log_t *log, u_char *buf, size_t len);
Igor Sysoev9e511812004-08-31 19:05:39 +000017
Igor Sysoevceb99292005-09-06 16:09:32 +000018#if (NGX_IMAP_SSL)
Igor Sysoev9fa5a822005-09-30 14:41:25 +000019static void ngx_imap_ssl_handshake_handler(ngx_connection_t *c);
Igor Sysoevceb99292005-09-06 16:09:32 +000020#endif
21
Igor Sysoev9e511812004-08-31 19:05:39 +000022
Igor Sysoev7b190b42005-06-07 15:56:31 +000023static ngx_str_t greetings[] = {
Igor Sysoev5192b362005-07-08 14:34:20 +000024 ngx_string("+OK POP3 ready" CRLF),
Igor Sysoev187b7d92005-07-14 12:51:53 +000025 ngx_string("* OK IMAP4 ready" CRLF)
Igor Sysoev7b190b42005-06-07 15:56:31 +000026};
27
Igor Sysoev85ef94b2005-06-23 13:41:06 +000028static ngx_str_t internal_server_errors[] = {
29 ngx_string("-ERR internal server error" CRLF),
30 ngx_string("* BAD internal server error" CRLF),
31};
32
Igor Sysoev7b190b42005-06-07 15:56:31 +000033static u_char pop3_ok[] = "+OK" CRLF;
34static u_char pop3_invalid_command[] = "-ERR invalid command" CRLF;
35
Igor Sysoev31eb8c02005-09-23 11:02:22 +000036static u_char imap_star[] = "* ";
Igor Sysoev187b7d92005-07-14 12:51:53 +000037static u_char imap_ok[] = "OK completed" CRLF;
Igor Sysoev5192b362005-07-08 14:34:20 +000038static u_char imap_next[] = "+ OK" CRLF;
39static u_char imap_bye[] = "* BYE" CRLF;
40static u_char imap_invalid_command[] = "BAD invalid command" CRLF;
41
Igor Sysoev7b190b42005-06-07 15:56:31 +000042
43void
44ngx_imap_init_connection(ngx_connection_t *c)
Igor Sysoev9e511812004-08-31 19:05:39 +000045{
Igor Sysoev9fa5a822005-09-30 14:41:25 +000046 ngx_imap_log_ctx_t *lctx;
Igor Sysoev31eb8c02005-09-23 11:02:22 +000047#if (NGX_IMAP_SSL)
Igor Sysoev9fa5a822005-09-30 14:41:25 +000048 ngx_imap_conf_ctx_t *ctx;
49 ngx_imap_ssl_conf_t *sslcf;
50 ngx_imap_core_srv_conf_t *cscf;
Igor Sysoev31eb8c02005-09-23 11:02:22 +000051#endif
Igor Sysoeve5733802005-09-08 14:36:09 +000052
Igor Sysoev9fa5a822005-09-30 14:41:25 +000053 ngx_log_error(NGX_LOG_INFO, c->log, 0, "*%ui client %V connected to %V",
54 c->number, &c->addr_text, &c->listening->addr_text);
Igor Sysoeve5733802005-09-08 14:36:09 +000055
Igor Sysoev31eb8c02005-09-23 11:02:22 +000056 lctx = ngx_palloc(c->pool, sizeof(ngx_imap_log_ctx_t));
57 if (lctx == NULL) {
Igor Sysoeve5733802005-09-08 14:36:09 +000058 ngx_imap_close_connection(c);
59 return;
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +000060 }
Igor Sysoeve5733802005-09-08 14:36:09 +000061
Igor Sysoev31eb8c02005-09-23 11:02:22 +000062 lctx->client = &c->addr_text;
63 lctx->session = NULL;
Igor Sysoeve5733802005-09-08 14:36:09 +000064
65 c->log->connection = c->number;
66 c->log->handler = ngx_imap_log_error;
Igor Sysoev31eb8c02005-09-23 11:02:22 +000067 c->log->data = lctx;
Igor Sysoeve5733802005-09-08 14:36:09 +000068 c->log->action = "sending client greeting line";
69
70 c->log_error = NGX_ERROR_INFO;
71
Igor Sysoev31eb8c02005-09-23 11:02:22 +000072#if (NGX_IMAP_SSL)
73
74 ctx = c->ctx;
75 sslcf = ngx_imap_get_module_srv_conf(ctx, ngx_imap_ssl_module);
76
77 if (sslcf->enable) {
Igor Sysoev9fa5a822005-09-30 14:41:25 +000078 if (ngx_ssl_create_connection(&sslcf->ssl, c, 0) == NGX_ERROR) {
Igor Sysoev31eb8c02005-09-23 11:02:22 +000079 ngx_imap_close_connection(c);
80 return;
81 }
82
Igor Sysoev9fa5a822005-09-30 14:41:25 +000083 if (ngx_ssl_handshake(c) == NGX_AGAIN) {
84
85 cscf = ngx_imap_get_module_srv_conf(ctx, ngx_imap_core_module);
86
87 ngx_add_timer(c->read, cscf->timeout);
88
89 c->ssl->handler = ngx_imap_ssl_handshake_handler;
90
91 return;
92 }
93
94 ngx_imap_ssl_handshake_handler(c);
95 return;
Igor Sysoev31eb8c02005-09-23 11:02:22 +000096 }
97
98#endif
99
Igor Sysoev9fa5a822005-09-30 14:41:25 +0000100 ngx_imap_init_session(c);
Igor Sysoeve5733802005-09-08 14:36:09 +0000101}
102
103
Igor Sysoev9fa5a822005-09-30 14:41:25 +0000104#if (NGX_IMAP_SSL)
105
Igor Sysoeve5733802005-09-08 14:36:09 +0000106static void
Igor Sysoev9fa5a822005-09-30 14:41:25 +0000107ngx_imap_ssl_handshake_handler(ngx_connection_t *c)
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +0000108{
Igor Sysoev9fa5a822005-09-30 14:41:25 +0000109 if (c->ssl->handshaked) {
110 ngx_imap_init_session(c);
111 return;
112 }
113
114 ngx_imap_close_connection(c);
115 return;
116}
117
118#endif
119
120
121static void
122ngx_imap_init_session(ngx_connection_t *c)
Igor Sysoeve5733802005-09-08 14:36:09 +0000123{
Igor Sysoevceb99292005-09-06 16:09:32 +0000124 ngx_imap_session_t *s;
Igor Sysoeve5733802005-09-08 14:36:09 +0000125 ngx_imap_log_ctx_t *lctx;
Igor Sysoev7b190b42005-06-07 15:56:31 +0000126 ngx_imap_conf_ctx_t *ctx;
Igor Sysoeve5733802005-09-08 14:36:09 +0000127 ngx_imap_core_srv_conf_t *cscf;
Igor Sysoev59cf56c2004-09-07 15:29:22 +0000128
Igor Sysoev9fa5a822005-09-30 14:41:25 +0000129 c->read->handler = ngx_imap_init_protocol;
130 c->write->handler = ngx_imap_send;
Igor Sysoevceb99292005-09-06 16:09:32 +0000131
132 s = ngx_pcalloc(c->pool, sizeof(ngx_imap_session_t));
133 if (s == NULL) {
Igor Sysoev59cf56c2004-09-07 15:29:22 +0000134 ngx_imap_close_connection(c);
135 return;
Igor Sysoev9e511812004-08-31 19:05:39 +0000136 }
Igor Sysoev59cf56c2004-09-07 15:29:22 +0000137
Igor Sysoev9fa5a822005-09-30 14:41:25 +0000138 ctx = c->ctx;
139 cscf = ngx_imap_get_module_srv_conf(ctx, ngx_imap_core_module);
140
Igor Sysoevceb99292005-09-06 16:09:32 +0000141 c->data = s;
142 s->connection = c;
Igor Sysoev2e6ba932004-09-09 15:40:48 +0000143
Igor Sysoevceb99292005-09-06 16:09:32 +0000144 s->protocol = cscf->protocol;
145
146 s->ctx = ngx_pcalloc(c->pool, sizeof(void *) * ngx_imap_max_module);
147 if (s->ctx == NULL) {
148 ngx_imap_session_internal_server_error(s);
149 return;
150 }
151
152 s->main_conf = ctx->main_conf;
153 s->srv_conf = ctx->srv_conf;
154
155 s->out = greetings[s->protocol];
156
Igor Sysoeve5733802005-09-08 14:36:09 +0000157 lctx = c->log->data;
158 lctx->session = s;
159
Igor Sysoev9fa5a822005-09-30 14:41:25 +0000160 ngx_add_timer(c->read, cscf->timeout);
Igor Sysoevceb99292005-09-06 16:09:32 +0000161
Igor Sysoev9fa5a822005-09-30 14:41:25 +0000162 if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) {
Igor Sysoev59cf56c2004-09-07 15:29:22 +0000163 ngx_imap_close_connection(c);
Igor Sysoev59cf56c2004-09-07 15:29:22 +0000164 }
Igor Sysoevceb99292005-09-06 16:09:32 +0000165
166 ngx_imap_send(c->write);
167}
168
169
170void
171ngx_imap_send(ngx_event_t *wev)
172{
Igor Sysoeve5733802005-09-08 14:36:09 +0000173 ngx_int_t n;
174 ngx_connection_t *c;
175 ngx_imap_session_t *s;
176 ngx_imap_core_srv_conf_t *cscf;
Igor Sysoevceb99292005-09-06 16:09:32 +0000177
178 c = wev->data;
179 s = c->data;
180
181 if (wev->timedout) {
182 ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +0000183 c->timedout = 1;
Igor Sysoevceb99292005-09-06 16:09:32 +0000184 ngx_imap_close_connection(c);
185 return;
186 }
187
188 if (s->out.len == 0) {
189 if (ngx_handle_write_event(c->write, 0) == NGX_ERROR) {
190 ngx_imap_close_connection(c);
191 }
192
193 return;
194 }
195
196 n = c->send(c, s->out.data, s->out.len);
197
198 if (n > 0) {
199 s->out.len -= n;
200
Igor Sysoeve5733802005-09-08 14:36:09 +0000201 if (wev->timer_set) {
202 ngx_del_timer(wev);
203 }
204
Igor Sysoevceb99292005-09-06 16:09:32 +0000205 if (s->quit) {
206 ngx_imap_close_connection(c);
207 return;
208 }
209
210 if (s->blocked) {
211 c->read->handler(c->read);
212 }
213
214 return;
215 }
216
217 if (n == NGX_ERROR) {
218 ngx_imap_close_connection(c);
219 return;
220 }
221
222 /* n == NGX_AGAIN */
223
Igor Sysoeve5733802005-09-08 14:36:09 +0000224 cscf = ngx_imap_get_module_srv_conf(s, ngx_imap_core_module);
225
226 ngx_add_timer(c->write, cscf->timeout);
227
Igor Sysoevceb99292005-09-06 16:09:32 +0000228 if (ngx_handle_write_event(c->write, 0) == NGX_ERROR) {
229 ngx_imap_close_connection(c);
230 return;
231 }
Igor Sysoev59cf56c2004-09-07 15:29:22 +0000232}
233
234
Igor Sysoev7b190b42005-06-07 15:56:31 +0000235static void
Igor Sysoeve5733802005-09-08 14:36:09 +0000236ngx_imap_init_protocol(ngx_event_t *rev)
Igor Sysoev59cf56c2004-09-07 15:29:22 +0000237{
Igor Sysoev7b190b42005-06-07 15:56:31 +0000238 size_t size;
239 ngx_connection_t *c;
240 ngx_imap_session_t *s;
Igor Sysoev7b190b42005-06-07 15:56:31 +0000241 ngx_imap_core_srv_conf_t *cscf;
Igor Sysoev59cf56c2004-09-07 15:29:22 +0000242
243 c = rev->data;
244
Igor Sysoeve5733802005-09-08 14:36:09 +0000245 c->log->action = "in auth state";
246
Igor Sysoev0292cbb2004-09-13 16:18:09 +0000247 if (rev->timedout) {
248 ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +0000249 c->timedout = 1;
Igor Sysoev0292cbb2004-09-13 16:18:09 +0000250 ngx_imap_close_connection(c);
251 return;
252 }
Igor Sysoev34a497e2004-09-09 18:55:39 +0000253
Igor Sysoevceb99292005-09-06 16:09:32 +0000254 s = c->data;
Igor Sysoev7b190b42005-06-07 15:56:31 +0000255
Igor Sysoev2e6ba932004-09-09 15:40:48 +0000256 if (ngx_array_init(&s->args, c->pool, 2, sizeof(ngx_str_t)) == NGX_ERROR) {
Igor Sysoev5192b362005-07-08 14:34:20 +0000257 ngx_imap_session_internal_server_error(s);
Igor Sysoev2e6ba932004-09-09 15:40:48 +0000258 return;
259 }
260
Igor Sysoevceb99292005-09-06 16:09:32 +0000261 if (s->protocol == NGX_IMAP_POP3_PROTOCOL) {
Igor Sysoev7b190b42005-06-07 15:56:31 +0000262 size = 128;
Igor Sysoev5192b362005-07-08 14:34:20 +0000263 s->imap_state = ngx_pop3_start;
Igor Sysoev7b190b42005-06-07 15:56:31 +0000264 c->read->handler = ngx_pop3_auth_state;
265
266 } else {
Igor Sysoevceb99292005-09-06 16:09:32 +0000267 cscf = ngx_imap_get_module_srv_conf(s, ngx_imap_core_module);
Igor Sysoev7b190b42005-06-07 15:56:31 +0000268 size = cscf->imap_client_buffer_size;
Igor Sysoev5192b362005-07-08 14:34:20 +0000269 s->imap_state = ngx_imap_start;
Igor Sysoev7b190b42005-06-07 15:56:31 +0000270 c->read->handler = ngx_imap_auth_state;
271 }
Igor Sysoev34a497e2004-09-09 18:55:39 +0000272
Igor Sysoev32e57712004-09-11 20:22:11 +0000273 s->buffer = ngx_create_temp_buf(c->pool, size);
Igor Sysoev2e6ba932004-09-09 15:40:48 +0000274 if (s->buffer == NULL) {
Igor Sysoev5192b362005-07-08 14:34:20 +0000275 ngx_imap_session_internal_server_error(s);
Igor Sysoev2e6ba932004-09-09 15:40:48 +0000276 return;
277 }
278
Igor Sysoev7b190b42005-06-07 15:56:31 +0000279 c->read->handler(rev);
Igor Sysoev59cf56c2004-09-07 15:29:22 +0000280}
281
282
Igor Sysoev5192b362005-07-08 14:34:20 +0000283void
Igor Sysoev7b190b42005-06-07 15:56:31 +0000284ngx_imap_auth_state(ngx_event_t *rev)
285{
Igor Sysoev31eb8c02005-09-23 11:02:22 +0000286 u_char *text, *last, *p, *dst, *src, *end;
Igor Sysoevceb99292005-09-06 16:09:32 +0000287 ssize_t text_len, last_len;
Igor Sysoev5192b362005-07-08 14:34:20 +0000288 ngx_str_t *arg;
289 ngx_int_t rc;
Igor Sysoev31eb8c02005-09-23 11:02:22 +0000290 ngx_uint_t tag, i;
Igor Sysoev5192b362005-07-08 14:34:20 +0000291 ngx_connection_t *c;
292 ngx_imap_session_t *s;
293 ngx_imap_core_srv_conf_t *cscf;
Igor Sysoev7b190b42005-06-07 15:56:31 +0000294
295 c = rev->data;
Igor Sysoev5192b362005-07-08 14:34:20 +0000296 s = c->data;
Igor Sysoev7b190b42005-06-07 15:56:31 +0000297
Igor Sysoev5192b362005-07-08 14:34:20 +0000298 ngx_log_debug0(NGX_LOG_DEBUG_IMAP, c->log, 0, "imap auth state");
299
300 if (rev->timedout) {
301 ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +0000302 c->timedout = 1;
Igor Sysoev5192b362005-07-08 14:34:20 +0000303 ngx_imap_close_connection(c);
304 return;
305 }
306
Igor Sysoevceb99292005-09-06 16:09:32 +0000307 if (s->out.len) {
308 ngx_log_debug0(NGX_LOG_DEBUG_IMAP, c->log, 0, "imap send handler busy");
309 s->blocked = 1;
310 return;
311 }
312
313 s->blocked = 0;
314
Igor Sysoev5192b362005-07-08 14:34:20 +0000315 rc = ngx_imap_read_command(s);
316
317 ngx_log_debug1(NGX_LOG_DEBUG_IMAP, c->log, 0, "imap auth: %i", rc);
318
319 if (rc == NGX_AGAIN || rc == NGX_ERROR) {
320 return;
321 }
322
Igor Sysoev5192b362005-07-08 14:34:20 +0000323 tag = 1;
324
325 text = NULL;
326 text_len = 0;
327
328 last = imap_ok;
329 last_len = sizeof(imap_ok) - 1;
330
331 if (rc == NGX_OK) {
332
333 ngx_log_debug1(NGX_LOG_DEBUG_IMAP, c->log, 0, "imap auth command: %i",
334 s->command);
335
Igor Sysoev31eb8c02005-09-23 11:02:22 +0000336 if (s->backslash) {
337
338 arg = s->args.elts;
339
340 for (i = 0; i < s->args.nelts; i++) {
341 dst = arg[i].data;
342 end = dst + arg[i].len;
343
344 for (src = dst; src < end; dst++) {
345 *dst = *src;
346 if (*src++ == '\\') {
347 *dst = *src++;
348 }
349 }
350
351 arg[i].len = dst - arg[i].data;
352 }
353
354 s->backslash = 0;
355 }
356
Igor Sysoev5192b362005-07-08 14:34:20 +0000357 switch (s->command) {
358
359 case NGX_IMAP_LOGIN:
Igor Sysoev9ac946b2005-10-24 15:09:41 +0000360 arg = s->args.elts;
Igor Sysoev5192b362005-07-08 14:34:20 +0000361
Igor Sysoev9ac946b2005-10-24 15:09:41 +0000362 if (s->args.nelts == 2 && arg[0].len) {
Igor Sysoev5192b362005-07-08 14:34:20 +0000363
364 s->login.len = arg[0].len;
365 s->login.data = ngx_palloc(c->pool, s->login.len);
366 if (s->login.data == NULL) {
367 ngx_imap_session_internal_server_error(s);
368 return;
369 }
370
371 ngx_memcpy(s->login.data, arg[0].data, s->login.len);
372
373 s->passwd.len = arg[1].len;
374 s->passwd.data = ngx_palloc(c->pool, s->passwd.len);
375 if (s->passwd.data == NULL) {
376 ngx_imap_session_internal_server_error(s);
377 return;
378 }
379
380 ngx_memcpy(s->passwd.data, arg[1].data, s->passwd.len);
381
Igor Sysoev9fa5a822005-09-30 14:41:25 +0000382#if (NGX_DEBUG_IMAP_PASSWD)
Igor Sysoev5192b362005-07-08 14:34:20 +0000383 ngx_log_debug2(NGX_LOG_DEBUG_IMAP, c->log, 0,
384 "imap login:\"%V\" passwd:\"%V\"",
385 &s->login, &s->passwd);
Igor Sysoev9fa5a822005-09-30 14:41:25 +0000386#else
387 ngx_log_debug1(NGX_LOG_DEBUG_IMAP, c->log, 0,
388 "imap login:\"%V\"", &s->login);
389#endif
Igor Sysoev5192b362005-07-08 14:34:20 +0000390
391 s->args.nelts = 0;
392 s->buffer->pos = s->buffer->start;
393 s->buffer->last = s->buffer->start;
394
395 if (rev->timer_set) {
396 ngx_del_timer(rev);
397 }
398
399 s->login_attempt++;
400
401 ngx_imap_auth_http_init(s);
402
403 return;
404
405 } else {
406 rc = NGX_IMAP_PARSE_INVALID_COMMAND;
407 }
408
409 break;
410
411 case NGX_IMAP_CAPABILITY:
412 cscf = ngx_imap_get_module_srv_conf(s, ngx_imap_core_module);
413 text = cscf->imap_capability->pos;
414 text_len = cscf->imap_capability->last - cscf->imap_capability->pos;
415 break;
416
417 case NGX_IMAP_LOGOUT:
Igor Sysoevceb99292005-09-06 16:09:32 +0000418 s->quit = 1;
Igor Sysoev5192b362005-07-08 14:34:20 +0000419 text = imap_bye;
420 text_len = sizeof(imap_bye) - 1;
Igor Sysoev5192b362005-07-08 14:34:20 +0000421 break;
422
423 case NGX_IMAP_NOOP:
424 break;
425
426 default:
427 rc = NGX_IMAP_PARSE_INVALID_COMMAND;
428 break;
429 }
430
431 } else if (rc == NGX_IMAP_NEXT) {
432 last = imap_next;
433 last_len = sizeof(imap_next) - 1;
434 tag = 0;
435 }
436
437 if (rc == NGX_IMAP_PARSE_INVALID_COMMAND) {
438 last = imap_invalid_command;
439 last_len = sizeof(imap_invalid_command) - 1;
440 }
441
442 if (tag) {
Igor Sysoev31eb8c02005-09-23 11:02:22 +0000443 if (s->tag.len == 0) {
444 s->tag.len = sizeof(imap_star) - 1;
445 s->tag.data = (u_char *) imap_star;
446 }
447
Igor Sysoevceb99292005-09-06 16:09:32 +0000448 if (s->tagged_line.len < s->tag.len + text_len + last_len) {
449 s->tagged_line.len = s->tag.len + text_len + last_len;
450 s->tagged_line.data = ngx_palloc(c->pool, s->tagged_line.len);
451 if (s->tagged_line.data == NULL) {
Igor Sysoev5192b362005-07-08 14:34:20 +0000452 ngx_imap_close_connection(c);
453 return;
454 }
455 }
456
Igor Sysoevceb99292005-09-06 16:09:32 +0000457 s->out.data = s->tagged_line.data;
458 s->out.len = s->tag.len + text_len + last_len;
459
460 p = s->out.data;
Igor Sysoev5192b362005-07-08 14:34:20 +0000461
462 if (text) {
463 p = ngx_cpymem(p, text, text_len);
464 }
465 p = ngx_cpymem(p, s->tag.data, s->tag.len);
466 ngx_memcpy(p, last, last_len);
467
Igor Sysoev5192b362005-07-08 14:34:20 +0000468
469 } else {
Igor Sysoevceb99292005-09-06 16:09:32 +0000470 s->out.data = last;
471 s->out.len = last_len;
Igor Sysoev5192b362005-07-08 14:34:20 +0000472 }
473
Igor Sysoevceb99292005-09-06 16:09:32 +0000474 if (rc != NGX_IMAP_NEXT) {
475 s->args.nelts = 0;
476 s->buffer->pos = s->buffer->start;
477 s->buffer->last = s->buffer->start;
478 s->tag.len = 0;
Igor Sysoev5192b362005-07-08 14:34:20 +0000479 }
480
Igor Sysoevceb99292005-09-06 16:09:32 +0000481 ngx_imap_send(c->write);
Igor Sysoev7b190b42005-06-07 15:56:31 +0000482}
483
484
Igor Sysoev5192b362005-07-08 14:34:20 +0000485void
Igor Sysoev7b190b42005-06-07 15:56:31 +0000486ngx_pop3_auth_state(ngx_event_t *rev)
Igor Sysoev34a497e2004-09-09 18:55:39 +0000487{
Igor Sysoev5192b362005-07-08 14:34:20 +0000488 u_char *text;
489 ssize_t size;
490 ngx_int_t rc;
Igor Sysoev5192b362005-07-08 14:34:20 +0000491 ngx_str_t *arg;
492 ngx_connection_t *c;
493 ngx_imap_session_t *s;
494 ngx_imap_core_srv_conf_t *cscf;
Igor Sysoev34a497e2004-09-09 18:55:39 +0000495
496 c = rev->data;
497 s = c->data;
498
Igor Sysoev10778352004-09-10 14:32:02 +0000499 ngx_log_debug0(NGX_LOG_DEBUG_IMAP, c->log, 0, "pop3 auth state");
500
Igor Sysoev0292cbb2004-09-13 16:18:09 +0000501 if (rev->timedout) {
502 ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +0000503 c->timedout = 1;
Igor Sysoev0292cbb2004-09-13 16:18:09 +0000504 ngx_imap_close_connection(c);
505 return;
506 }
Igor Sysoev34a497e2004-09-09 18:55:39 +0000507
Igor Sysoevceb99292005-09-06 16:09:32 +0000508 if (s->out.len) {
509 ngx_log_debug0(NGX_LOG_DEBUG_IMAP, c->log, 0, "imap send handler busy");
510 s->blocked = 1;
511 return;
512 }
513
514 s->blocked = 0;
515
Igor Sysoev5192b362005-07-08 14:34:20 +0000516 rc = ngx_imap_read_command(s);
Igor Sysoev34a497e2004-09-09 18:55:39 +0000517
518 if (rc == NGX_AGAIN || rc == NGX_ERROR) {
519 return;
520 }
521
Igor Sysoev10778352004-09-10 14:32:02 +0000522 text = pop3_ok;
523 size = sizeof(pop3_ok) - 1;
524
525 if (rc == NGX_OK) {
526 switch (s->imap_state) {
527
528 case ngx_pop3_start:
529
530 switch (s->command) {
531
532 case NGX_POP3_USER:
533 if (s->args.nelts == 1) {
534 s->imap_state = ngx_pop3_user;
Igor Sysoev32e57712004-09-11 20:22:11 +0000535
536 arg = s->args.elts;
537 s->login.len = arg[0].len;
Igor Sysoev5192b362005-07-08 14:34:20 +0000538 s->login.data = ngx_palloc(c->pool, s->login.len);
Igor Sysoev32e57712004-09-11 20:22:11 +0000539 if (s->login.data == NULL) {
Igor Sysoev5192b362005-07-08 14:34:20 +0000540 ngx_imap_session_internal_server_error(s);
Igor Sysoev32e57712004-09-11 20:22:11 +0000541 return;
542 }
543
Igor Sysoev5192b362005-07-08 14:34:20 +0000544 ngx_memcpy(s->login.data, arg[0].data, s->login.len);
Igor Sysoev32e57712004-09-11 20:22:11 +0000545
546 ngx_log_debug1(NGX_LOG_DEBUG_IMAP, c->log, 0,
Igor Sysoev5192b362005-07-08 14:34:20 +0000547 "pop3 login: \"%V\"", &s->login);
Igor Sysoev32e57712004-09-11 20:22:11 +0000548
Igor Sysoev10778352004-09-10 14:32:02 +0000549 } else {
550 rc = NGX_IMAP_PARSE_INVALID_COMMAND;
551 }
552
553 break;
554
Igor Sysoev5192b362005-07-08 14:34:20 +0000555 case NGX_POP3_CAPA:
556 cscf = ngx_imap_get_module_srv_conf(s, ngx_imap_core_module);
557 text = cscf->pop3_capability->pos;
558 size = cscf->pop3_capability->last - cscf->pop3_capability->pos;
559 break;
560
Igor Sysoev10778352004-09-10 14:32:02 +0000561 case NGX_POP3_QUIT:
Igor Sysoevceb99292005-09-06 16:09:32 +0000562 s->quit = 1;
Igor Sysoev10778352004-09-10 14:32:02 +0000563 break;
564
Igor Sysoev5192b362005-07-08 14:34:20 +0000565 case NGX_POP3_NOOP:
566 break;
567
Igor Sysoev10778352004-09-10 14:32:02 +0000568 default:
569 s->imap_state = ngx_pop3_start;
570 rc = NGX_IMAP_PARSE_INVALID_COMMAND;
571 break;
572 }
573
574 break;
575
576 case ngx_pop3_user:
577
578 switch (s->command) {
579
580 case NGX_POP3_PASS:
581 if (s->args.nelts == 1) {
582 /* STUB */ s->imap_state = ngx_pop3_start;
Igor Sysoev32e57712004-09-11 20:22:11 +0000583
584 arg = s->args.elts;
585 s->passwd.len = arg[0].len;
Igor Sysoev5192b362005-07-08 14:34:20 +0000586 s->passwd.data = ngx_palloc(c->pool, s->passwd.len);
Igor Sysoev32e57712004-09-11 20:22:11 +0000587 if (s->passwd.data == NULL) {
Igor Sysoev5192b362005-07-08 14:34:20 +0000588 ngx_imap_session_internal_server_error(s);
Igor Sysoev32e57712004-09-11 20:22:11 +0000589 return;
590 }
591
Igor Sysoev5192b362005-07-08 14:34:20 +0000592 ngx_memcpy(s->passwd.data, arg[0].data, s->passwd.len);
Igor Sysoev32e57712004-09-11 20:22:11 +0000593
Igor Sysoev9fa5a822005-09-30 14:41:25 +0000594#if (NGX_DEBUG_IMAP_PASSWD)
Igor Sysoev32e57712004-09-11 20:22:11 +0000595 ngx_log_debug1(NGX_LOG_DEBUG_IMAP, c->log, 0,
Igor Sysoev5192b362005-07-08 14:34:20 +0000596 "pop3 passwd: \"%V\"", &s->passwd);
Igor Sysoev9fa5a822005-09-30 14:41:25 +0000597#endif
Igor Sysoev32e57712004-09-11 20:22:11 +0000598
Igor Sysoev5192b362005-07-08 14:34:20 +0000599 s->args.nelts = 0;
Igor Sysoev32e57712004-09-11 20:22:11 +0000600 s->buffer->pos = s->buffer->start;
601 s->buffer->last = s->buffer->start;
602
Igor Sysoev5192b362005-07-08 14:34:20 +0000603 if (rev->timer_set) {
604 ngx_del_timer(rev);
605 }
606
Igor Sysoev7b190b42005-06-07 15:56:31 +0000607 ngx_imap_auth_http_init(s);
Igor Sysoev32e57712004-09-11 20:22:11 +0000608
609 return;
610
Igor Sysoev10778352004-09-10 14:32:02 +0000611 } else {
612 rc = NGX_IMAP_PARSE_INVALID_COMMAND;
613 }
614
615 break;
616
Igor Sysoev5192b362005-07-08 14:34:20 +0000617 case NGX_POP3_CAPA:
618 cscf = ngx_imap_get_module_srv_conf(s, ngx_imap_core_module);
619 text = cscf->pop3_capability->pos;
620 size = cscf->pop3_capability->last - cscf->pop3_capability->pos;
621 break;
622
Igor Sysoev10778352004-09-10 14:32:02 +0000623 case NGX_POP3_QUIT:
Igor Sysoevceb99292005-09-06 16:09:32 +0000624 s->quit = 1;
Igor Sysoev10778352004-09-10 14:32:02 +0000625 break;
626
Igor Sysoev5192b362005-07-08 14:34:20 +0000627 case NGX_POP3_NOOP:
628 break;
629
Igor Sysoev10778352004-09-10 14:32:02 +0000630 default:
631 s->imap_state = ngx_pop3_start;
632 rc = NGX_IMAP_PARSE_INVALID_COMMAND;
633 break;
634 }
635
636 break;
Igor Sysoev5192b362005-07-08 14:34:20 +0000637
638 /* suppress warinings */
639 case ngx_pop3_passwd:
640 break;
Igor Sysoev10778352004-09-10 14:32:02 +0000641 }
642 }
Igor Sysoev34a497e2004-09-09 18:55:39 +0000643
644 if (rc == NGX_IMAP_PARSE_INVALID_COMMAND) {
645 text = pop3_invalid_command;
646 size = sizeof(pop3_invalid_command) - 1;
Igor Sysoev34a497e2004-09-09 18:55:39 +0000647 }
648
Igor Sysoev10778352004-09-10 14:32:02 +0000649 s->args.nelts = 0;
650 s->buffer->pos = s->buffer->start;
651 s->buffer->last = s->buffer->start;
Igor Sysoevceb99292005-09-06 16:09:32 +0000652
653 s->out.data = text;
654 s->out.len = size;
655
656 ngx_imap_send(c->write);
Igor Sysoev34a497e2004-09-09 18:55:39 +0000657}
658
659
Igor Sysoev7b190b42005-06-07 15:56:31 +0000660static ngx_int_t
Igor Sysoev5192b362005-07-08 14:34:20 +0000661ngx_imap_read_command(ngx_imap_session_t *s)
Igor Sysoev34a497e2004-09-09 18:55:39 +0000662{
663 ssize_t n;
664 ngx_int_t rc;
665
Igor Sysoevceb99292005-09-06 16:09:32 +0000666 n = s->connection->recv(s->connection, s->buffer->last,
667 s->buffer->end - s->buffer->last);
Igor Sysoev34a497e2004-09-09 18:55:39 +0000668
669 if (n == NGX_ERROR || n == 0) {
670 ngx_imap_close_connection(s->connection);
671 return NGX_ERROR;
672 }
673
674 if (n > 0) {
675 s->buffer->last += n;
676 }
677
678 if (n == NGX_AGAIN) {
679 if (ngx_handle_read_event(s->connection->read, 0) == NGX_ERROR) {
Igor Sysoev5192b362005-07-08 14:34:20 +0000680 ngx_imap_session_internal_server_error(s);
Igor Sysoev34a497e2004-09-09 18:55:39 +0000681 return NGX_ERROR;
682 }
683
684 return NGX_AGAIN;
685 }
686
Igor Sysoev5192b362005-07-08 14:34:20 +0000687 if (s->protocol == NGX_IMAP_POP3_PROTOCOL) {
688 rc = ngx_pop3_parse_command(s);
689 } else {
690 rc = ngx_imap_parse_command(s);
691 }
Igor Sysoev34a497e2004-09-09 18:55:39 +0000692
Igor Sysoev5192b362005-07-08 14:34:20 +0000693 if (rc == NGX_AGAIN
694 || rc == NGX_IMAP_NEXT
695 || rc == NGX_IMAP_PARSE_INVALID_COMMAND)
696 {
Igor Sysoev34a497e2004-09-09 18:55:39 +0000697 return rc;
698 }
699
700 if (rc == NGX_ERROR) {
701 ngx_imap_close_connection(s->connection);
702 return NGX_ERROR;
703 }
704
705 return NGX_OK;
706}
707
708
Igor Sysoev7b190b42005-06-07 15:56:31 +0000709void
Igor Sysoev85ef94b2005-06-23 13:41:06 +0000710ngx_imap_session_internal_server_error(ngx_imap_session_t *s)
711{
Igor Sysoevceb99292005-09-06 16:09:32 +0000712 s->out = internal_server_errors[s->protocol];
713 s->quit = 1;
Igor Sysoev85ef94b2005-06-23 13:41:06 +0000714
Igor Sysoevceb99292005-09-06 16:09:32 +0000715 ngx_imap_send(s->connection->write);
Igor Sysoev85ef94b2005-06-23 13:41:06 +0000716}
717
718
719void
Igor Sysoev7b190b42005-06-07 15:56:31 +0000720ngx_imap_close_connection(ngx_connection_t *c)
Igor Sysoev59cf56c2004-09-07 15:29:22 +0000721{
Igor Sysoev02025fd2005-01-18 13:03:58 +0000722 ngx_pool_t *pool;
723
Igor Sysoev59cf56c2004-09-07 15:29:22 +0000724 ngx_log_debug1(NGX_LOG_DEBUG_IMAP, c->log, 0,
725 "close imap connection: %d", c->fd);
726
Igor Sysoevceb99292005-09-06 16:09:32 +0000727#if (NGX_IMAP_SSL)
728
729 if (c->ssl) {
730 if (ngx_ssl_shutdown(c) == NGX_AGAIN) {
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +0000731 c->ssl->handler = ngx_imap_close_connection;
Igor Sysoevceb99292005-09-06 16:09:32 +0000732 return;
733 }
734 }
735
736#endif
737
Igor Sysoev31eb8c02005-09-23 11:02:22 +0000738 c->closed = 1;
739
Igor Sysoev02025fd2005-01-18 13:03:58 +0000740 pool = c->pool;
741
Igor Sysoev59cf56c2004-09-07 15:29:22 +0000742 ngx_close_connection(c);
Igor Sysoev02025fd2005-01-18 13:03:58 +0000743
Igor Sysoevc1571722005-03-19 12:38:37 +0000744 ngx_destroy_pool(pool);
Igor Sysoev9e511812004-08-31 19:05:39 +0000745}
Igor Sysoevceb99292005-09-06 16:09:32 +0000746
747
Igor Sysoeve5733802005-09-08 14:36:09 +0000748static u_char *
749ngx_imap_log_error(ngx_log_t *log, u_char *buf, size_t len)
750{
Igor Sysoev055951d2005-10-21 19:12:18 +0000751 u_char *p;
752 ngx_imap_session_t *s;
753 ngx_imap_log_ctx_t *ctx;
Igor Sysoeve5733802005-09-08 14:36:09 +0000754
755 if (log->action) {
756 p = ngx_snprintf(buf, len, " while %s", log->action);
757 len -= p - buf;
758 buf = p;
759 }
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +0000760
Igor Sysoeve5733802005-09-08 14:36:09 +0000761 ctx = log->data;
762
763 p = ngx_snprintf(buf, len, ", client: %V", ctx->client);
764 len -= p - buf;
765 buf = p;
766
767 s = ctx->session;
768
769 if (s == NULL) {
770 return p;
771 }
772
773 p = ngx_snprintf(buf, len, ", server: %V",
774 &s->connection->listening->addr_text);
775 len -= p - buf;
776 buf = p;
777
778 if (s->login.len == 0) {
779 return p;
780 }
781
782 p = ngx_snprintf(buf, len, ", login: \"%V\"", &s->login);
783 len -= p - buf;
784 buf = p;
785
786 if (s->proxy == NULL) {
787 return p;
788 }
789
790 p = ngx_snprintf(buf, len, ", upstream: %V",
791 &s->proxy->upstream.peers->peer[0].name);
792
793 return p;
794}