comparison src/imap/ngx_imap_handler.c @ 76:da9a3b14312d NGINX_0_1_38

nginx 0.1.38 *) Feature: the "limit_rate" directive is supported in in proxy and FastCGI mode. *) Feature: the "X-Accel-Limit-Rate" response header line is supported in proxy and FastCGI mode. *) Feature: the "break" directive. *) Feature: the "log_not_found" directive. *) Bugfix: the response status code was not changed when request was redirected by the ""X-Accel-Redirect" header line. *) Bugfix: the variables set by the "set" directive could not be used in SSI. *) Bugfix: the segmentation fault may occurred if the SSI page has more than one remote subrequest. *) Bugfix: nginx treated the backend response as invalid if the status line in the header was transferred in two packets; bug appeared in 0.1.29. *) Feature: the "ssi_types" directive. *) Feature: the "autoindex_exact_size" directive. *) Bugfix: the ngx_http_autoindex_module did not support the long file names in UTF-8. *) Feature: the IMAP/POP3 proxy.
author Igor Sysoev <http://sysoev.ru>
date Fri, 08 Jul 2005 00:00:00 +0400
parents
children 9db7e0b5b27f
comparison
equal deleted inserted replaced
75:985847bb65f9 76:da9a3b14312d
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_imap.h>
11
12
13 static void ngx_imap_init_session(ngx_event_t *rev);
14 static ngx_int_t ngx_imap_read_command(ngx_imap_session_t *s);
15
16
17 static ngx_str_t greetings[] = {
18 ngx_string("+OK POP3 ready" CRLF),
19 ngx_string("* OK IMAP ready" CRLF)
20 };
21
22 static ngx_str_t internal_server_errors[] = {
23 ngx_string("-ERR internal server error" CRLF),
24 ngx_string("* BAD internal server error" CRLF),
25 };
26
27 static u_char pop3_ok[] = "+OK" CRLF;
28 static u_char pop3_invalid_command[] = "-ERR invalid command" CRLF;
29
30 static u_char imap_ok[] = "OK" CRLF;
31 static u_char imap_next[] = "+ OK" CRLF;
32 static u_char imap_bye[] = "* BYE" CRLF;
33 static u_char imap_invalid_command[] = "BAD invalid command" CRLF;
34
35
36 void
37 ngx_imap_init_connection(ngx_connection_t *c)
38 {
39 ssize_t size;
40 ngx_imap_conf_ctx_t *ctx;
41 ngx_imap_core_srv_conf_t *cscf;
42
43 ngx_log_debug0(NGX_LOG_DEBUG_IMAP, c->log, 0, "imap init connection");
44
45 c->log_error = NGX_ERROR_INFO;
46
47 ctx = c->ctx;
48 cscf = ngx_imap_get_module_srv_conf(ctx, ngx_imap_core_module);
49
50 size = greetings[cscf->protocol].len;
51
52 if (ngx_send(c, greetings[cscf->protocol].data, size) < size) {
53 /*
54 * we treat the incomplete sending as NGX_ERROR
55 * because it is very strange here
56 */
57 ngx_imap_close_connection(c);
58 return;
59 }
60
61 c->read->handler = ngx_imap_init_session;
62
63 ngx_add_timer(c->read, cscf->timeout);
64
65 if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) {
66 ngx_imap_close_connection(c);
67 }
68 }
69
70
71 static void
72 ngx_imap_init_session(ngx_event_t *rev)
73 {
74 size_t size;
75 ngx_connection_t *c;
76 ngx_imap_session_t *s;
77 ngx_imap_conf_ctx_t *ctx;
78 ngx_imap_core_srv_conf_t *cscf;
79
80 c = rev->data;
81
82 if (rev->timedout) {
83 ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
84 ngx_imap_close_connection(c);
85 return;
86 }
87
88 s = ngx_pcalloc(c->pool, sizeof(ngx_imap_session_t));
89 if (s == NULL) {
90 ngx_imap_session_internal_server_error(s);
91 return;
92 }
93
94 c->data = s;
95 s->connection = c;
96
97 s->ctx = ngx_pcalloc(c->pool, sizeof(void *) * ngx_imap_max_module);
98 if (s->ctx == NULL) {
99 ngx_imap_session_internal_server_error(s);
100 return;
101 }
102
103 ctx = c->ctx;
104 s->main_conf = ctx->main_conf;
105 s->srv_conf = ctx->srv_conf;
106
107 if (ngx_array_init(&s->args, c->pool, 2, sizeof(ngx_str_t)) == NGX_ERROR) {
108 ngx_imap_session_internal_server_error(s);
109 return;
110 }
111
112 cscf = ngx_imap_get_module_srv_conf(s, ngx_imap_core_module);
113
114 s->protocol = cscf->protocol;
115
116 if (cscf->protocol == NGX_IMAP_POP3_PROTOCOL) {
117 size = 128;
118 s->imap_state = ngx_pop3_start;
119 c->read->handler = ngx_pop3_auth_state;
120
121 } else {
122 size = cscf->imap_client_buffer_size;
123 s->imap_state = ngx_imap_start;
124 c->read->handler = ngx_imap_auth_state;
125 }
126
127 s->buffer = ngx_create_temp_buf(c->pool, size);
128 if (s->buffer == NULL) {
129 ngx_imap_session_internal_server_error(s);
130 return;
131 }
132
133 c->read->handler(rev);
134 }
135
136
137 void
138 ngx_imap_auth_state(ngx_event_t *rev)
139 {
140 u_char *text, *last, *out, *p;
141 ssize_t size, text_len, last_len;
142 ngx_str_t *arg;
143 ngx_int_t rc;
144 ngx_uint_t quit, tag;
145 ngx_connection_t *c;
146 ngx_imap_session_t *s;
147 ngx_imap_core_srv_conf_t *cscf;
148
149 c = rev->data;
150 s = c->data;
151
152 ngx_log_debug0(NGX_LOG_DEBUG_IMAP, c->log, 0, "imap auth state");
153
154 if (rev->timedout) {
155 ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
156 ngx_imap_close_connection(c);
157 return;
158 }
159
160 rc = ngx_imap_read_command(s);
161
162 ngx_log_debug1(NGX_LOG_DEBUG_IMAP, c->log, 0, "imap auth: %i", rc);
163
164 if (rc == NGX_AGAIN || rc == NGX_ERROR) {
165 return;
166 }
167
168 quit = 0;
169 tag = 1;
170
171 text = NULL;
172 text_len = 0;
173
174 last = imap_ok;
175 last_len = sizeof(imap_ok) - 1;
176
177 if (rc == NGX_OK) {
178
179 ngx_log_debug1(NGX_LOG_DEBUG_IMAP, c->log, 0, "imap auth command: %i",
180 s->command);
181
182 switch (s->command) {
183
184 case NGX_IMAP_LOGIN:
185 if (s->args.nelts == 2) {
186
187 arg = s->args.elts;
188
189 s->login.len = arg[0].len;
190 s->login.data = ngx_palloc(c->pool, s->login.len);
191 if (s->login.data == NULL) {
192 ngx_imap_session_internal_server_error(s);
193 return;
194 }
195
196 ngx_memcpy(s->login.data, arg[0].data, s->login.len);
197
198 s->passwd.len = arg[1].len;
199 s->passwd.data = ngx_palloc(c->pool, s->passwd.len);
200 if (s->passwd.data == NULL) {
201 ngx_imap_session_internal_server_error(s);
202 return;
203 }
204
205 ngx_memcpy(s->passwd.data, arg[1].data, s->passwd.len);
206
207 ngx_log_debug2(NGX_LOG_DEBUG_IMAP, c->log, 0,
208 "imap login:\"%V\" passwd:\"%V\"",
209 &s->login, &s->passwd);
210
211 s->args.nelts = 0;
212 s->buffer->pos = s->buffer->start;
213 s->buffer->last = s->buffer->start;
214
215 if (rev->timer_set) {
216 ngx_del_timer(rev);
217 }
218
219 s->login_attempt++;
220
221 ngx_imap_auth_http_init(s);
222
223 return;
224
225 } else {
226 rc = NGX_IMAP_PARSE_INVALID_COMMAND;
227 }
228
229 break;
230
231 case NGX_IMAP_CAPABILITY:
232 cscf = ngx_imap_get_module_srv_conf(s, ngx_imap_core_module);
233 text = cscf->imap_capability->pos;
234 text_len = cscf->imap_capability->last - cscf->imap_capability->pos;
235 break;
236
237 case NGX_IMAP_LOGOUT:
238 text = imap_bye;
239 text_len = sizeof(imap_bye) - 1;
240 quit = 1;
241 break;
242
243 case NGX_IMAP_NOOP:
244 break;
245
246 default:
247 rc = NGX_IMAP_PARSE_INVALID_COMMAND;
248 break;
249 }
250
251 } else if (rc == NGX_IMAP_NEXT) {
252 last = imap_next;
253 last_len = sizeof(imap_next) - 1;
254 tag = 0;
255 }
256
257 if (rc == NGX_IMAP_PARSE_INVALID_COMMAND) {
258 last = imap_invalid_command;
259 last_len = sizeof(imap_invalid_command) - 1;
260 }
261
262 if (tag) {
263 if (s->out.len < text_len + s->tag.len + last_len) {
264
265 s->out.len = text_len + s->tag.len + last_len;
266 s->out.data = ngx_palloc(c->pool, s->out.len);
267 if (s->out.data == NULL) {
268 ngx_imap_close_connection(c);
269 return;
270 }
271 }
272
273 out = s->out.data;
274 p = out;
275
276 if (text) {
277 p = ngx_cpymem(p, text, text_len);
278 }
279 p = ngx_cpymem(p, s->tag.data, s->tag.len);
280 ngx_memcpy(p, last, last_len);
281
282 size = text_len + s->tag.len + last_len;
283
284 } else {
285 out = last;
286 size = last_len;
287 }
288
289 if (ngx_send(c, out, size) < size) {
290 /*
291 * we treat the incomplete sending as NGX_ERROR
292 * because it is very strange here
293 */
294 ngx_imap_close_connection(c);
295 return;
296 }
297
298 if (rc == NGX_IMAP_NEXT) {
299 return;
300 }
301
302 if (quit) {
303 ngx_imap_close_connection(c);
304 return;
305 }
306
307 s->args.nelts = 0;
308 s->buffer->pos = s->buffer->start;
309 s->buffer->last = s->buffer->start;
310 s->tag.len = 0;
311 }
312
313
314 void
315 ngx_pop3_auth_state(ngx_event_t *rev)
316 {
317 u_char *text;
318 ssize_t size;
319 ngx_int_t rc;
320 ngx_uint_t quit;
321 ngx_str_t *arg;
322 ngx_connection_t *c;
323 ngx_imap_session_t *s;
324 ngx_imap_core_srv_conf_t *cscf;
325
326 c = rev->data;
327 s = c->data;
328
329 ngx_log_debug0(NGX_LOG_DEBUG_IMAP, c->log, 0, "pop3 auth state");
330
331 if (rev->timedout) {
332 ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
333 ngx_imap_close_connection(c);
334 return;
335 }
336
337 rc = ngx_imap_read_command(s);
338
339 if (rc == NGX_AGAIN || rc == NGX_ERROR) {
340 return;
341 }
342
343 quit = 0;
344 text = pop3_ok;
345 size = sizeof(pop3_ok) - 1;
346
347 if (rc == NGX_OK) {
348 switch (s->imap_state) {
349
350 case ngx_pop3_start:
351
352 switch (s->command) {
353
354 case NGX_POP3_USER:
355 if (s->args.nelts == 1) {
356 s->imap_state = ngx_pop3_user;
357
358 arg = s->args.elts;
359 s->login.len = arg[0].len;
360 s->login.data = ngx_palloc(c->pool, s->login.len);
361 if (s->login.data == NULL) {
362 ngx_imap_session_internal_server_error(s);
363 return;
364 }
365
366 ngx_memcpy(s->login.data, arg[0].data, s->login.len);
367
368 ngx_log_debug1(NGX_LOG_DEBUG_IMAP, c->log, 0,
369 "pop3 login: \"%V\"", &s->login);
370
371 } else {
372 rc = NGX_IMAP_PARSE_INVALID_COMMAND;
373 }
374
375 break;
376
377 case NGX_POP3_CAPA:
378 cscf = ngx_imap_get_module_srv_conf(s, ngx_imap_core_module);
379 text = cscf->pop3_capability->pos;
380 size = cscf->pop3_capability->last - cscf->pop3_capability->pos;
381 break;
382
383 case NGX_POP3_QUIT:
384 quit = 1;
385 break;
386
387 case NGX_POP3_NOOP:
388 break;
389
390 default:
391 s->imap_state = ngx_pop3_start;
392 rc = NGX_IMAP_PARSE_INVALID_COMMAND;
393 break;
394 }
395
396 break;
397
398 case ngx_pop3_user:
399
400 switch (s->command) {
401
402 case NGX_POP3_PASS:
403 if (s->args.nelts == 1) {
404 /* STUB */ s->imap_state = ngx_pop3_start;
405
406 arg = s->args.elts;
407 s->passwd.len = arg[0].len;
408 s->passwd.data = ngx_palloc(c->pool, s->passwd.len);
409 if (s->passwd.data == NULL) {
410 ngx_imap_session_internal_server_error(s);
411 return;
412 }
413
414 ngx_memcpy(s->passwd.data, arg[0].data, s->passwd.len);
415
416 ngx_log_debug1(NGX_LOG_DEBUG_IMAP, c->log, 0,
417 "pop3 passwd: \"%V\"", &s->passwd);
418
419 s->args.nelts = 0;
420 s->buffer->pos = s->buffer->start;
421 s->buffer->last = s->buffer->start;
422
423 if (rev->timer_set) {
424 ngx_del_timer(rev);
425 }
426
427 ngx_imap_auth_http_init(s);
428
429 return;
430
431 } else {
432 rc = NGX_IMAP_PARSE_INVALID_COMMAND;
433 }
434
435 break;
436
437 case NGX_POP3_CAPA:
438 cscf = ngx_imap_get_module_srv_conf(s, ngx_imap_core_module);
439 text = cscf->pop3_capability->pos;
440 size = cscf->pop3_capability->last - cscf->pop3_capability->pos;
441 break;
442
443 case NGX_POP3_QUIT:
444 quit = 1;
445 break;
446
447 case NGX_POP3_NOOP:
448 break;
449
450 default:
451 s->imap_state = ngx_pop3_start;
452 rc = NGX_IMAP_PARSE_INVALID_COMMAND;
453 break;
454 }
455
456 break;
457
458 /* suppress warinings */
459 case ngx_pop3_passwd:
460 break;
461 }
462 }
463
464 if (rc == NGX_IMAP_PARSE_INVALID_COMMAND) {
465 text = pop3_invalid_command;
466 size = sizeof(pop3_invalid_command) - 1;
467 }
468
469 if (ngx_send(c, text, size) < size) {
470 /*
471 * we treat the incomplete sending as NGX_ERROR
472 * because it is very strange here
473 */
474 ngx_imap_close_connection(c);
475 return;
476 }
477
478 if (quit) {
479 ngx_imap_close_connection(c);
480 return;
481 }
482
483 s->args.nelts = 0;
484 s->buffer->pos = s->buffer->start;
485 s->buffer->last = s->buffer->start;
486 }
487
488
489 static ngx_int_t
490 ngx_imap_read_command(ngx_imap_session_t *s)
491 {
492 ssize_t n;
493 ngx_int_t rc;
494
495 n = ngx_recv(s->connection, s->buffer->last,
496 s->buffer->end - s->buffer->last);
497
498 if (n == NGX_ERROR || n == 0) {
499 ngx_imap_close_connection(s->connection);
500 return NGX_ERROR;
501 }
502
503 if (n > 0) {
504 s->buffer->last += n;
505 }
506
507 if (n == NGX_AGAIN) {
508 if (ngx_handle_read_event(s->connection->read, 0) == NGX_ERROR) {
509 ngx_imap_session_internal_server_error(s);
510 return NGX_ERROR;
511 }
512
513 return NGX_AGAIN;
514 }
515
516 if (s->protocol == NGX_IMAP_POP3_PROTOCOL) {
517 rc = ngx_pop3_parse_command(s);
518 } else {
519 rc = ngx_imap_parse_command(s);
520 }
521
522 if (rc == NGX_AGAIN
523 || rc == NGX_IMAP_NEXT
524 || rc == NGX_IMAP_PARSE_INVALID_COMMAND)
525 {
526 return rc;
527 }
528
529 if (rc == NGX_ERROR) {
530 ngx_imap_close_connection(s->connection);
531 return NGX_ERROR;
532 }
533
534 return NGX_OK;
535 }
536
537
538 void
539 ngx_imap_session_internal_server_error(ngx_imap_session_t *s)
540 {
541 (void) ngx_send(s->connection, internal_server_errors[s->protocol].data,
542 internal_server_errors[s->protocol].len);
543
544 ngx_imap_close_connection(s->connection);
545 }
546
547
548 void
549 ngx_imap_close_connection(ngx_connection_t *c)
550 {
551 ngx_pool_t *pool;
552
553 ngx_log_debug1(NGX_LOG_DEBUG_IMAP, c->log, 0,
554 "close imap connection: %d", c->fd);
555
556 pool = c->pool;
557
558 ngx_close_connection(c);
559
560 ngx_destroy_pool(pool);
561 }