~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Nginx/mail/ngx_mail_handler.c

Version: ~ [ nginx-0.6.26 ] ~ [ nginx-0.5.35 ] ~ [ nginx-0.5.20 ] ~ [ nginx-0.5.19 ] ~

  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_mail.h>
 11 
 12 
 13 static void ngx_mail_init_session(ngx_connection_t *c);
 14 
 15 #if (NGX_MAIL_SSL)
 16 static void ngx_mail_ssl_init_connection(ngx_ssl_t *ssl, ngx_connection_t *c);
 17 static void ngx_mail_ssl_handshake_handler(ngx_connection_t *c);
 18 #endif
 19 
 20 
 21 void
 22 ngx_mail_init_connection(ngx_connection_t *c)
 23 {
 24     in_addr_t             in_addr;
 25     socklen_t             len;
 26     ngx_uint_t            i;
 27     struct sockaddr_in    sin;
 28     ngx_mail_log_ctx_t   *ctx;
 29     ngx_mail_in_port_t   *imip;
 30     ngx_mail_in_addr_t   *imia;
 31     ngx_mail_session_t   *s;
 32 
 33     /* find the server configuration for the address:port */
 34 
 35     /* AF_INET only */
 36 
 37     imip = c->listening->servers;
 38     imia = imip->addrs;
 39 
 40     i = 0;
 41 
 42     if (imip->naddrs > 1) {
 43 
 44         /*
 45          * There are several addresses on this port and one of them
 46          * is the "*:port" wildcard so getsockname() is needed to determine
 47          * the server address.
 48          *
 49          * AcceptEx() already gave this address.
 50          */
 51 
 52 #if (NGX_WIN32)
 53         if (c->local_sockaddr) {
 54             in_addr =
 55                    ((struct sockaddr_in *) c->local_sockaddr)->sin_addr.s_addr;
 56 
 57         } else
 58 #endif
 59         {
 60             len = sizeof(struct sockaddr_in);
 61             if (getsockname(c->fd, (struct sockaddr *) &sin, &len) == -1) {
 62                 ngx_connection_error(c, ngx_socket_errno,
 63                                      "getsockname() failed");
 64                 ngx_mail_close_connection(c);
 65                 return;
 66             }
 67 
 68             in_addr = sin.sin_addr.s_addr;
 69         }
 70 
 71         /* the last address is "*" */
 72 
 73         for ( /* void */ ; i < imip->naddrs - 1; i++) {
 74             if (in_addr == imia[i].addr) {
 75                 break;
 76             }
 77         }
 78     }
 79 
 80 
 81     s = ngx_pcalloc(c->pool, sizeof(ngx_mail_session_t));
 82     if (s == NULL) {
 83         ngx_mail_close_connection(c);
 84         return;
 85     }
 86 
 87     s->main_conf = imia[i].ctx->main_conf;
 88     s->srv_conf = imia[i].ctx->srv_conf;
 89 
 90     s->addr_text = &imia[i].addr_text;
 91 
 92     c->data = s;
 93     s->connection = c;
 94 
 95     ngx_log_error(NGX_LOG_INFO, c->log, 0, "*%ui client %V connected to %V",
 96                   c->number, &c->addr_text, s->addr_text);
 97 
 98     ctx = ngx_palloc(c->pool, sizeof(ngx_mail_log_ctx_t));
 99     if (ctx == NULL) {
100         ngx_mail_close_connection(c);
101         return;
102     }
103 
104     ctx->client = &c->addr_text;
105     ctx->session = s;
106 
107     c->log->connection = c->number;
108     c->log->handler = ngx_mail_log_error;
109     c->log->data = ctx;
110     c->log->action = "sending client greeting line";
111 
112     c->log_error = NGX_ERROR_INFO;
113 
114 #if (NGX_MAIL_SSL)
115     {
116     ngx_mail_ssl_conf_t  *sslcf;
117 
118     sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
119 
120     if (sslcf->enable) {
121         ngx_mail_ssl_init_connection(&sslcf->ssl, c);
122         return;
123     }
124     }
125 #endif
126 
127     ngx_mail_init_session(c);
128 }
129 
130 
131 #if (NGX_MAIL_SSL)
132 
133 void
134 ngx_mail_starttls_handler(ngx_event_t *rev)
135 {
136     ngx_connection_t     *c;
137     ngx_mail_session_t   *s;
138     ngx_mail_ssl_conf_t  *sslcf;
139 
140     c = rev->data;
141     s = c->data;
142     s->starttls = 1;
143 
144     c->log->action = "in starttls state";
145 
146     sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
147 
148     ngx_mail_ssl_init_connection(&sslcf->ssl, c);
149 }
150 
151 
152 static void
153 ngx_mail_ssl_init_connection(ngx_ssl_t *ssl, ngx_connection_t *c)
154 {
155     ngx_mail_session_t        *s;
156     ngx_mail_core_srv_conf_t  *cscf;
157 
158     if (ngx_ssl_create_connection(ssl, c, 0) == NGX_ERROR) {
159         ngx_mail_close_connection(c);
160         return;
161     }
162 
163     if (ngx_ssl_handshake(c) == NGX_AGAIN) {
164 
165         s = c->data;
166 
167         cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
168 
169         ngx_add_timer(c->read, cscf->timeout);
170 
171         c->ssl->handler = ngx_mail_ssl_handshake_handler;
172 
173         return;
174     }
175 
176     ngx_mail_ssl_handshake_handler(c);
177 }
178 
179 
180 static void
181 ngx_mail_ssl_handshake_handler(ngx_connection_t *c)
182 {
183     ngx_mail_session_t        *s;
184     ngx_mail_core_srv_conf_t  *cscf;
185 
186     if (c->ssl->handshaked) {
187 
188         s = c->data;
189 
190         if (s->starttls) {
191             cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
192 
193             c->read->handler = cscf->protocol->init_protocol;
194             c->write->handler = ngx_mail_send;
195 
196             cscf->protocol->init_protocol(c->read);
197 
198             return;
199         }
200 
201         ngx_mail_init_session(c);
202         return;
203     }
204 
205     ngx_mail_close_connection(c);
206 }
207 
208 #endif
209 
210 
211 static void
212 ngx_mail_init_session(ngx_connection_t *c)
213 {
214     ngx_mail_session_t        *s;
215     ngx_mail_core_srv_conf_t  *cscf;
216 
217     s = c->data;
218 
219     cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
220 
221     s->protocol = cscf->protocol->type;
222 
223     s->ctx = ngx_pcalloc(c->pool, sizeof(void *) * ngx_mail_max_module);
224     if (s->ctx == NULL) {
225         ngx_mail_session_internal_server_error(s);
226         return;
227     }
228 
229     c->write->handler = ngx_mail_send;
230 
231     cscf->protocol->init_session(s, c);
232 }
233 
234 
235 ngx_int_t
236 ngx_mail_salt(ngx_mail_session_t *s, ngx_connection_t *c,
237     ngx_mail_core_srv_conf_t *cscf)
238 {
239     s->salt.data = ngx_palloc(c->pool,
240                               sizeof(" <18446744073709551616.@>" CRLF) - 1
241                               + NGX_TIME_T_LEN
242                               + cscf->server_name.len);
243     if (s->salt.data == NULL) {
244         return NGX_ERROR;
245     }
246 
247     s->salt.len = ngx_sprintf(s->salt.data, "<%ul.%T@%V>" CRLF,
248                               ngx_random(), ngx_time(), &cscf->server_name)
249                   - s->salt.data;
250 
251     return NGX_OK;
252 }
253 
254 
255 #if (NGX_MAIL_SSL)
256 
257 ngx_int_t
258 ngx_mail_starttls_only(ngx_mail_session_t *s, ngx_connection_t *c)
259 {
260     ngx_mail_ssl_conf_t  *sslcf;
261 
262     if (c->ssl) {
263         return 0;
264     }
265 
266     sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
267 
268     if (sslcf->starttls == NGX_MAIL_STARTTLS_ONLY) {
269         return 1;
270     }
271 
272     return 0;
273 }
274 
275 #endif
276 
277 
278 ngx_int_t
279 ngx_mail_auth_plain(ngx_mail_session_t *s, ngx_connection_t *c, ngx_uint_t n)
280 {
281     u_char     *p, *last;
282     ngx_str_t  *arg, plain;
283 
284     arg = s->args.elts;
285 
286 #if (NGX_DEBUG_MAIL_PASSWD)
287     ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
288                    "mail auth plain: \"%V\"", &arg[n]);
289 #endif
290 
291     plain.data = ngx_palloc(c->pool, ngx_base64_decoded_length(arg[n].len));
292     if (plain.data == NULL){
293         return NGX_ERROR;
294     }
295 
296     if (ngx_decode_base64(&plain, &arg[n]) != NGX_OK) {
297         ngx_log_error(NGX_LOG_INFO, c->log, 0,
298             "client sent invalid base64 encoding in AUTH PLAIN command");
299         return NGX_MAIL_PARSE_INVALID_COMMAND;
300     }
301 
302     p = plain.data;
303     last = p + plain.len;
304 
305     while (p < last && *p++) { /* void */ }
306 
307     if (p == last) {
308         ngx_log_error(NGX_LOG_INFO, c->log, 0,
309                       "client sent invalid login in AUTH PLAIN command");
310         return NGX_MAIL_PARSE_INVALID_COMMAND;
311     }
312 
313     s->login.data = p;
314 
315     while (p < last && *p) { p++; }
316 
317     if (p == last) {
318         ngx_log_error(NGX_LOG_INFO, c->log, 0,
319                       "client sent invalid password in AUTH PLAIN command");
320         return NGX_MAIL_PARSE_INVALID_COMMAND;
321     }
322 
323     s->login.len = p++ - s->login.data;
324 
325     s->passwd.len = last - p;
326     s->passwd.data = p;
327 
328 #if (NGX_DEBUG_MAIL_PASSWD)
329     ngx_log_debug2(NGX_LOG_DEBUG_MAIL, c->log, 0,
330                    "mail auth plain: \"%V\" \"%V\"", &s->login, &s->passwd);
331 #endif
332 
333     return NGX_DONE;
334 }
335 
336 
337 ngx_int_t
338 ngx_mail_auth_login_username(ngx_mail_session_t *s, ngx_connection_t *c)
339 {
340     ngx_str_t  *arg;
341 
342     arg = s->args.elts;
343 
344     ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
345                    "mail auth login username: \"%V\"", &arg[0]);
346 
347     s->login.data = ngx_palloc(c->pool, ngx_base64_decoded_length(arg[0].len));
348     if (s->login.data == NULL){
349         return NGX_ERROR;
350     }
351 
352     if (ngx_decode_base64(&s->login, &arg[0]) != NGX_OK) {
353         ngx_log_error(NGX_LOG_INFO, c->log, 0,
354             "client sent invalid base64 encoding in AUTH LOGIN command");
355         return NGX_MAIL_PARSE_INVALID_COMMAND;
356     }
357 
358     ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
359                    "mail auth login username: \"%V\"", &s->login);
360 
361     return NGX_OK;
362 }
363 
364 
365 ngx_int_t
366 ngx_mail_auth_login_password(ngx_mail_session_t *s, ngx_connection_t *c)
367 {
368     ngx_str_t  *arg;
369 
370     arg = s->args.elts;
371 
372 #if (NGX_DEBUG_MAIL_PASSWD)
373     ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
374                    "mail auth login password: \"%V\"", &arg[0]);
375 #endif
376 
377     s->passwd.data = ngx_palloc(c->pool, ngx_base64_decoded_length(arg[0].len));
378     if (s->passwd.data == NULL){
379         return NGX_ERROR;
380     }
381 
382     if (ngx_decode_base64(&s->passwd, &arg[0]) != NGX_OK) {
383         ngx_log_error(NGX_LOG_INFO, c->log, 0,
384             "client sent invalid base64 encoding in AUTH LOGIN command");
385         return NGX_MAIL_PARSE_INVALID_COMMAND;
386     }
387 
388 #if (NGX_DEBUG_MAIL_PASSWD)
389     ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
390                    "mail auth login password: \"%V\"", &s->passwd);
391 #endif
392 
393     return NGX_DONE;
394 }
395 
396 
397 ngx_int_t
398 ngx_mail_auth_cram_md5_salt(ngx_mail_session_t *s, ngx_connection_t *c,
399     char *prefix, size_t len)
400 {
401     u_char      *p;
402     ngx_str_t    salt;
403     ngx_uint_t   n;
404 
405     p = ngx_palloc(c->pool, len + ngx_base64_encoded_length(s->salt.len) + 2);
406     if (p == NULL) {
407         return NGX_ERROR;
408     }
409 
410     salt.data = ngx_cpymem(p, prefix, len);
411     s->salt.len -= 2;
412 
413     ngx_encode_base64(&salt, &s->salt);
414 
415     s->salt.len += 2;
416     n = len + salt.len;
417     p[n++] = CR; p[n++] = LF;
418 
419     s->out.len = n;
420     s->out.data = p;
421 
422     return NGX_OK;
423 }
424 
425 
426 ngx_int_t
427 ngx_mail_auth_cram_md5(ngx_mail_session_t *s, ngx_connection_t *c)
428 {
429     u_char     *p, *last;
430     ngx_str_t  *arg;
431 
432     arg = s->args.elts;
433 
434     ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
435                    "mail auth cram-md5: \"%V\"", &arg[0]);
436 
437     s->login.data = ngx_palloc(c->pool, ngx_base64_decoded_length(arg[0].len));
438     if (s->login.data == NULL){
439         return NGX_ERROR;
440     }
441 
442     if (ngx_decode_base64(&s->login, &arg[0]) != NGX_OK) {
443         ngx_log_error(NGX_LOG_INFO, c->log, 0,
444             "client sent invalid base64 encoding in AUTH CRAM-MD5 command");
445         return NGX_MAIL_PARSE_INVALID_COMMAND;
446     }
447 
448     p = s->login.data;
449     last = p + s->login.len;
450 
451     while (p < last) {
452         if (*p++ == ' ') {
453             s->login.len = p - s->login.data - 1;
454             s->passwd.len = last - p;
455             s->passwd.data = p;
456             break;
457         }
458     }
459 
460     if (s->passwd.len != 32) {
461         ngx_log_error(NGX_LOG_INFO, c->log, 0,
462             "client sent invalid CRAM-MD5 hash in AUTH CRAM-MD5 command");
463         return NGX_MAIL_PARSE_INVALID_COMMAND;
464     }
465 
466     ngx_log_debug2(NGX_LOG_DEBUG_MAIL, c->log, 0,
467                    "mail auth cram-md5: \"%V\" \"%V\"", &s->login, &s->passwd);
468 
469     s->auth_method = NGX_MAIL_AUTH_CRAM_MD5;
470 
471     return NGX_DONE;
472 }
473 
474 
475 void
476 ngx_mail_send(ngx_event_t *wev)
477 {
478     ngx_int_t                  n;
479     ngx_connection_t          *c;
480     ngx_mail_session_t        *s;
481     ngx_mail_core_srv_conf_t  *cscf;
482 
483     c = wev->data;
484     s = c->data;
485 
486     if (wev->timedout) {
487         ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
488         c->timedout = 1;
489         ngx_mail_close_connection(c);
490         return;
491     }
492 
493     if (s->out.len == 0) {
494         if (ngx_handle_write_event(c->write, 0) == NGX_ERROR) {
495             ngx_mail_close_connection(c);
496         }
497 
498         return;
499     }
500 
501     n = c->send(c, s->out.data, s->out.len);
502 
503     if (n > 0) {
504         s->out.len -= n;
505 
506         if (wev->timer_set) {
507             ngx_del_timer(wev);
508         }
509 
510         if (s->quit) {
511             ngx_mail_close_connection(c);
512             return;
513         }
514 
515         if (s->blocked) {
516             c->read->handler(c->read);
517         }
518 
519         return;
520     }
521 
522     if (n == NGX_ERROR) {
523         ngx_mail_close_connection(c);
524         return;
525     }
526 
527     /* n == NGX_AGAIN */
528 
529     cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
530 
531     ngx_add_timer(c->write, cscf->timeout);
532 
533     if (ngx_handle_write_event(c->write, 0) == NGX_ERROR) {
534         ngx_mail_close_connection(c);
535         return;
536     }
537 }
538 
539 
540 ngx_int_t
541 ngx_mail_read_command(ngx_mail_session_t *s, ngx_connection_t *c)
542 {
543     ssize_t                    n;
544     ngx_int_t                  rc;
545     ngx_str_t                  l;
546     ngx_mail_core_srv_conf_t  *cscf;
547 
548     n = c->recv(c, s->buffer->last, s->buffer->end - s->buffer->last);
549 
550     if (n == NGX_ERROR || n == 0) {
551         ngx_mail_close_connection(c);
552         return NGX_ERROR;
553     }
554 
555     if (n > 0) {
556         s->buffer->last += n;
557     }
558 
559     if (n == NGX_AGAIN) {
560         if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) {
561             ngx_mail_session_internal_server_error(s);
562             return NGX_ERROR;
563         }
564 
565         return NGX_AGAIN;
566     }
567 
568     cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
569 
570     rc = cscf->protocol->parse_command(s);
571 
572     if (rc == NGX_AGAIN) {
573 
574         if (s->buffer->last < s->buffer->end) {
575             return rc;
576         }
577 
578         l.len = s->buffer->last - s->buffer->start;
579         l.data = s->buffer->start;
580 
581         ngx_log_error(NGX_LOG_INFO, c->log, 0,
582                       "client sent too long command \"%V\"", &l);
583 
584         s->quit = 1;
585 
586         return NGX_MAIL_PARSE_INVALID_COMMAND;
587     }
588 
589     if (rc == NGX_IMAP_NEXT || rc == NGX_MAIL_PARSE_INVALID_COMMAND) {
590         return rc;
591     }
592 
593     if (rc == NGX_ERROR) {
594         ngx_mail_close_connection(c);
595         return NGX_ERROR;
596     }
597 
598     return NGX_OK;
599 }
600 
601 
602 void
603 ngx_mail_auth(ngx_mail_session_t *s, ngx_connection_t *c)
604 {
605     s->args.nelts = 0;
606     s->buffer->pos = s->buffer->start;
607     s->buffer->last = s->buffer->start;
608     s->state = 0;
609 
610     if (c->read->timer_set) {
611         ngx_del_timer(c->read);
612     }
613 
614     s->login_attempt++;
615 
616     ngx_mail_auth_http_init(s);
617 }
618 
619 
620 void
621 ngx_mail_session_internal_server_error(ngx_mail_session_t *s)
622 {
623     ngx_mail_core_srv_conf_t  *cscf;
624 
625     cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
626 
627     s->out = cscf->protocol->internal_server_error;
628     s->quit = 1;
629 
630     ngx_mail_send(s->connection->write);
631 }
632 
633 
634 void
635 ngx_mail_close_connection(ngx_connection_t *c)
636 {
637     ngx_pool_t  *pool;
638 
639     ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
640                    "close mail connection: %d", c->fd);
641 
642 #if (NGX_MAIL_SSL)
643 
644     if (c->ssl) {
645         if (ngx_ssl_shutdown(c) == NGX_AGAIN) {
646             c->ssl->handler = ngx_mail_close_connection;
647             return;
648         }
649     }
650 
651 #endif
652 
653 #if (NGX_STAT_STUB)
654     ngx_atomic_fetch_add(ngx_stat_active, -1);
655 #endif
656 
657     c->destroyed = 1;
658 
659     pool = c->pool;
660 
661     ngx_close_connection(c);
662 
663     ngx_destroy_pool(pool);
664 }
665 
666 
667 u_char *
668 ngx_mail_log_error(ngx_log_t *log, u_char *buf, size_t len)
669 {
670     u_char              *p;
671     ngx_mail_session_t  *s;
672     ngx_mail_log_ctx_t  *ctx;
673 
674     if (log->action) {
675         p = ngx_snprintf(buf, len, " while %s", log->action);
676         len -= p - buf;
677         buf = p;
678     }
679 
680     ctx = log->data;
681 
682     p = ngx_snprintf(buf, len, ", client: %V", ctx->client);
683     len -= p - buf;
684     buf = p;
685 
686     s = ctx->session;
687 
688     if (s == NULL) {
689         return p;
690     }
691 
692     p = ngx_snprintf(buf, len, "%s, server: %V",
693                      s->starttls ? " using starttls" : "",
694                      s->addr_text);
695     len -= p - buf;
696     buf = p;
697 
698     if (s->login.len == 0) {
699         return p;
700     }
701 
702     p = ngx_snprintf(buf, len, ", login: \"%V\"", &s->login);
703     len -= p - buf;
704     buf = p;
705 
706     if (s->proxy == NULL) {
707         return p;
708     }
709 
710     p = ngx_snprintf(buf, len, ", upstream: %V", s->proxy->upstream.name);
711 
712     return p;
713 }
714 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.