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

Linux Cross Reference
Nginx/mail/ngx_mail_handler.c

Version: ~ [ nginx-0.8.20 ] ~ [ nginx-0.7.62 ] ~ [ nginx-0.6.39 ] ~

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

~ [ 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.