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

Linux Cross Reference
Nginx/mail/ngx_mail_smtp_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 #include <ngx_mail_smtp_module.h>
 12 
 13 
 14 static void ngx_mail_smtp_invalid_pipelining(ngx_event_t *rev);
 15 static ngx_int_t ngx_mail_smtp_create_buffer(ngx_mail_session_t *s,
 16     ngx_connection_t *c);
 17 
 18 static ngx_int_t ngx_mail_smtp_helo(ngx_mail_session_t *s, ngx_connection_t *c);
 19 static ngx_int_t ngx_mail_smtp_auth(ngx_mail_session_t *s, ngx_connection_t *c);
 20 static ngx_int_t ngx_mail_smtp_mail(ngx_mail_session_t *s, ngx_connection_t *c);
 21 static ngx_int_t ngx_mail_smtp_starttls(ngx_mail_session_t *s,
 22     ngx_connection_t *c);
 23 
 24 static ngx_int_t ngx_mail_smtp_discard_command(ngx_mail_session_t *s,
 25     ngx_connection_t *c, char *err);
 26 static void ngx_mail_smtp_log_rejected_command(ngx_mail_session_t *s,
 27     ngx_connection_t *c, char *err);
 28 
 29 
 30 static u_char  smtp_ok[] = "250 2.0.0 OK" CRLF;
 31 static u_char  smtp_bye[] = "221 2.0.0 Bye" CRLF;
 32 static u_char  smtp_starttls[] = "220 2.0.0 Start TLS" CRLF;
 33 static u_char  smtp_next[] = "334 " CRLF;
 34 static u_char  smtp_username[] = "334 VXNlcm5hbWU6" CRLF;
 35 static u_char  smtp_password[] = "334 UGFzc3dvcmQ6" CRLF;
 36 static u_char  smtp_invalid_command[] = "500 5.5.1 Invalid command" CRLF;
 37 static u_char  smtp_invalid_pipelining[] =
 38    "503 5.5.0 Improper use of SMTP command pipelining" CRLF;
 39 static u_char  smtp_invalid_argument[] = "501 5.5.4 Invalid argument" CRLF;
 40 static u_char  smtp_auth_required[] = "530 5.7.1 Authentication required" CRLF;
 41 
 42 
 43 void
 44 ngx_mail_smtp_init_session(ngx_mail_session_t *s, ngx_connection_t *c)
 45 {
 46     ngx_msec_t                 timeout;
 47     ngx_mail_core_srv_conf_t  *cscf;
 48     ngx_mail_smtp_srv_conf_t  *sscf;
 49 
 50     cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
 51     sscf = ngx_mail_get_module_srv_conf(s, ngx_mail_smtp_module);
 52 
 53     timeout = sscf->greeting_delay ? sscf->greeting_delay : cscf->timeout;
 54     ngx_add_timer(c->read, timeout);
 55 
 56     if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) {
 57         ngx_mail_close_connection(c);
 58     }
 59 
 60     if (sscf->greeting_delay) {
 61          c->read->handler = ngx_mail_smtp_invalid_pipelining;
 62          return;
 63     }
 64 
 65     c->read->handler = ngx_mail_smtp_init_protocol;
 66 
 67     s->out = sscf->greeting;
 68 
 69     ngx_mail_send(c->write);
 70 }
 71 
 72 
 73 static void
 74 ngx_mail_smtp_invalid_pipelining(ngx_event_t *rev)
 75 {
 76     ngx_connection_t          *c;
 77     ngx_mail_session_t        *s;
 78     ngx_mail_core_srv_conf_t  *cscf;
 79     ngx_mail_smtp_srv_conf_t  *sscf;
 80 
 81     c = rev->data;
 82     s = c->data;
 83 
 84     c->log->action = "in delay pipelining state";
 85 
 86     if (rev->timedout) {
 87 
 88         ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "delay greeting");
 89 
 90         rev->timedout = 0;
 91 
 92         cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
 93 
 94         c->read->handler = ngx_mail_smtp_init_protocol;
 95 
 96         ngx_add_timer(c->read, cscf->timeout);
 97 
 98         if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) {
 99             ngx_mail_close_connection(c);
100             return;
101         }
102 
103         sscf = ngx_mail_get_module_srv_conf(s, ngx_mail_smtp_module);
104 
105         s->out = sscf->greeting;
106 
107     } else {
108 
109         ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "invalid pipelining");
110 
111         if (s->buffer == NULL) {
112             if (ngx_mail_smtp_create_buffer(s, c) != NGX_OK) {
113                 return;
114             }
115         }
116 
117         if (ngx_mail_smtp_discard_command(s, c,
118                                 "client was rejected before greeting: \"%V\"")
119             != NGX_OK)
120         {
121             return;
122         }
123 
124         s->out.len = sizeof(smtp_invalid_pipelining) - 1;
125         s->out.data = smtp_invalid_pipelining;
126     }
127 
128     ngx_mail_send(c->write);
129 }
130 
131 
132 void
133 ngx_mail_smtp_init_protocol(ngx_event_t *rev)
134 {
135     ngx_connection_t    *c;
136     ngx_mail_session_t  *s;
137 
138     c = rev->data;
139 
140     c->log->action = "in auth state";
141 
142     if (rev->timedout) {
143         ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
144         c->timedout = 1;
145         ngx_mail_close_connection(c);
146         return;
147     }
148 
149     s = c->data;
150 
151     if (s->buffer == NULL) {
152         if (ngx_mail_smtp_create_buffer(s, c) != NGX_OK) {
153             return;
154         }
155     }
156 
157     s->mail_state = ngx_smtp_start;
158     c->read->handler = ngx_mail_smtp_auth_state;
159 
160     ngx_mail_smtp_auth_state(rev);
161 }
162 
163 
164 static ngx_int_t
165 ngx_mail_smtp_create_buffer(ngx_mail_session_t *s, ngx_connection_t *c)
166 {
167     ngx_mail_smtp_srv_conf_t  *sscf;
168 
169     if (ngx_array_init(&s->args, c->pool, 2, sizeof(ngx_str_t)) == NGX_ERROR) {
170         ngx_mail_session_internal_server_error(s);
171         return NGX_ERROR;
172     }
173 
174     sscf = ngx_mail_get_module_srv_conf(s, ngx_mail_smtp_module);
175 
176     s->buffer = ngx_create_temp_buf(c->pool, sscf->client_buffer_size);
177     if (s->buffer == NULL) {
178         ngx_mail_session_internal_server_error(s);
179         return NGX_ERROR;
180     }
181 
182     return NGX_OK;
183 }
184 
185 
186 void
187 ngx_mail_smtp_auth_state(ngx_event_t *rev)
188 {
189     ngx_int_t            rc;
190     ngx_connection_t    *c;
191     ngx_mail_session_t  *s;
192 
193     c = rev->data;
194     s = c->data;
195 
196     ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "smtp auth state");
197 
198     if (rev->timedout) {
199         ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
200         c->timedout = 1;
201         ngx_mail_close_connection(c);
202         return;
203     }
204 
205     if (s->out.len) {
206         ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "smtp send handler busy");
207         s->blocked = 1;
208         return;
209     }
210 
211     s->blocked = 0;
212 
213     rc = ngx_mail_read_command(s, c);
214 
215     if (rc == NGX_AGAIN || rc == NGX_ERROR) {
216         return;
217     }
218 
219     s->out.len = sizeof(smtp_ok) - 1;
220     s->out.data = smtp_ok;
221 
222     if (rc == NGX_OK) {
223         switch (s->mail_state) {
224 
225         case ngx_smtp_start:
226 
227             switch (s->command) {
228 
229             case NGX_SMTP_HELO:
230             case NGX_SMTP_EHLO:
231                 rc = ngx_mail_smtp_helo(s, c);
232                 break;
233 
234             case NGX_SMTP_AUTH:
235                 rc = ngx_mail_smtp_auth(s, c);
236                 break;
237 
238             case NGX_SMTP_QUIT:
239                 s->quit = 1;
240                 s->out.len = sizeof(smtp_bye) - 1;
241                 s->out.data = smtp_bye;
242                 break;
243 
244             case NGX_SMTP_MAIL:
245                 rc = ngx_mail_smtp_mail(s, c);
246                 break;
247 
248             case NGX_SMTP_NOOP:
249             case NGX_SMTP_RSET:
250                 break;
251 
252             case NGX_SMTP_STARTTLS:
253                 rc = ngx_mail_smtp_starttls(s, c);
254                 s->out.len = sizeof(smtp_starttls) - 1;
255                 s->out.data = smtp_starttls;
256                 break;
257 
258             default:
259                 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
260                 break;
261             }
262 
263             break;
264 
265         case ngx_smtp_auth_login_username:
266             rc = ngx_mail_auth_login_username(s, c);
267 
268             s->out.len = sizeof(smtp_password) - 1;
269             s->out.data = smtp_password;
270             s->mail_state = ngx_smtp_auth_login_password;
271             break;
272 
273         case ngx_smtp_auth_login_password:
274             rc = ngx_mail_auth_login_password(s, c);
275             break;
276 
277         case ngx_smtp_auth_plain:
278             rc = ngx_mail_auth_plain(s, c, 0);
279             break;
280 
281         case ngx_smtp_auth_cram_md5:
282             rc = ngx_mail_auth_cram_md5(s, c);
283             break;
284         }
285     }
286 
287     switch (rc) {
288 
289     case NGX_DONE:
290         ngx_mail_auth(s, c);
291         return;
292 
293     case NGX_ERROR:
294         ngx_mail_session_internal_server_error(s);
295         return;
296 
297     case NGX_MAIL_PARSE_INVALID_COMMAND:
298         s->mail_state = ngx_smtp_start;
299         s->state = 0;
300 
301         s->out.len = sizeof(smtp_invalid_command) - 1;
302         s->out.data = smtp_invalid_command;
303 
304         /* fall through */
305 
306     case NGX_OK:
307         s->args.nelts = 0;
308         s->buffer->pos = s->buffer->start;
309         s->buffer->last = s->buffer->start;
310 
311         if (s->state) {
312             s->arg_start = s->buffer->start;
313         }
314 
315         ngx_mail_send(c->write);
316     }
317 }
318 
319 
320 static ngx_int_t
321 ngx_mail_smtp_helo(ngx_mail_session_t *s, ngx_connection_t *c)
322 {
323     ngx_str_t                 *arg;
324     ngx_mail_smtp_srv_conf_t  *sscf;
325 
326     if (s->args.nelts != 1) {
327         s->out.len = sizeof(smtp_invalid_argument) - 1;
328         s->out.data = smtp_invalid_argument;
329         s->state = 0;
330         return NGX_OK;
331     }
332 
333     arg = s->args.elts;
334 
335     s->smtp_helo.len = arg[0].len;
336 
337     s->smtp_helo.data = ngx_palloc(c->pool, arg[0].len);
338     if (s->smtp_helo.data == NULL) {
339         return NGX_ERROR;
340     }
341 
342     ngx_memcpy(s->smtp_helo.data, arg[0].data, arg[0].len);
343 
344     sscf = ngx_mail_get_module_srv_conf(s, ngx_mail_smtp_module);
345 
346     if (s->command == NGX_SMTP_HELO) {
347         s->out = sscf->server_name;
348 
349     } else {
350         s->esmtp = 1;
351 
352 #if (NGX_MAIL_SSL)
353 
354         if (c->ssl == NULL) {
355             ngx_mail_ssl_conf_t  *sslcf;
356 
357             sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
358 
359             if (sslcf->starttls == NGX_MAIL_STARTTLS_ON) {
360                 s->out = sscf->starttls_capability;
361                 return NGX_OK;
362             }
363 
364             if (sslcf->starttls == NGX_MAIL_STARTTLS_ONLY) {
365                 s->out = sscf->starttls_only_capability;
366                 return NGX_OK;
367             }
368         }
369 #endif
370 
371         s->out = sscf->capability;
372     }
373 
374     return NGX_OK;
375 }
376 
377 
378 static ngx_int_t
379 ngx_mail_smtp_auth(ngx_mail_session_t *s, ngx_connection_t *c)
380 {
381     ngx_int_t                  rc;
382     ngx_mail_core_srv_conf_t  *cscf;
383     ngx_mail_smtp_srv_conf_t  *sscf;
384 
385 #if (NGX_MAIL_SSL)
386     if (ngx_mail_starttls_only(s, c)) {
387         return NGX_MAIL_PARSE_INVALID_COMMAND;
388     }
389 #endif
390 
391     if (s->args.nelts == 0) {
392         s->out.len = sizeof(smtp_invalid_argument) - 1;
393         s->out.data = smtp_invalid_argument;
394         s->state = 0;
395         return NGX_OK;
396     }
397 
398     rc = ngx_mail_auth_parse(s, c);
399 
400     switch (rc) {
401 
402     case NGX_MAIL_AUTH_LOGIN:
403 
404         s->out.len = sizeof(smtp_username) - 1;
405         s->out.data = smtp_username;
406         s->mail_state = ngx_smtp_auth_login_username;
407 
408         return NGX_OK;
409 
410     case NGX_MAIL_AUTH_PLAIN:
411 
412         s->out.len = sizeof(smtp_next) - 1;
413         s->out.data = smtp_next;
414         s->mail_state = ngx_smtp_auth_plain;
415 
416         return NGX_OK;
417 
418     case NGX_MAIL_AUTH_CRAM_MD5:
419 
420         sscf = ngx_mail_get_module_srv_conf(s, ngx_mail_smtp_module);
421 
422         if (!(sscf->auth_methods & NGX_MAIL_AUTH_CRAM_MD5_ENABLED)) {
423             return NGX_MAIL_PARSE_INVALID_COMMAND;
424         }
425 
426         if (s->salt.data == NULL) {
427             cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
428 
429             if (ngx_mail_salt(s, c, cscf) != NGX_OK) {
430                 return NGX_ERROR;
431             }
432         }
433 
434         if (ngx_mail_auth_cram_md5_salt(s, c, "334 ", 4) == NGX_OK) {
435             s->mail_state = ngx_smtp_auth_cram_md5;
436             return NGX_OK;
437         }
438 
439         return NGX_ERROR;
440     }
441 
442     return rc;
443 }
444 
445 
446 static ngx_int_t
447 ngx_mail_smtp_mail(ngx_mail_session_t *s, ngx_connection_t *c)
448 {
449     ngx_mail_smtp_log_rejected_command(s, c, "client was rejected: \"%V\"");
450 
451     s->out.len = sizeof(smtp_auth_required) - 1;
452     s->out.data = smtp_auth_required;
453 
454     return NGX_OK;
455 }
456 
457 
458 static ngx_int_t
459 ngx_mail_smtp_starttls(ngx_mail_session_t *s, ngx_connection_t *c)
460 {
461 #if (NGX_MAIL_SSL)
462     ngx_mail_ssl_conf_t  *sslcf;
463 
464     if (c->ssl == NULL) {
465         sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
466         if (sslcf->starttls) {
467 
468             /*
469              * RFC3207 requires us to discard any knowledge
470              * obtained from client before STARTTLS.
471              */
472 
473             s->smtp_helo.len = 0;
474             s->smtp_helo.data = NULL;
475 
476             c->read->handler = ngx_mail_starttls_handler;
477             return NGX_OK;
478         }
479     }
480 
481 #endif
482 
483     return NGX_MAIL_PARSE_INVALID_COMMAND;
484 }
485 
486 
487 static ngx_int_t
488 ngx_mail_smtp_discard_command(ngx_mail_session_t *s, ngx_connection_t *c,
489     char *err)
490 {
491     ssize_t    n;
492 
493     n = c->recv(c, s->buffer->last, s->buffer->end - s->buffer->last);
494 
495     if (n == NGX_ERROR || n == 0) {
496         ngx_mail_close_connection(c);
497         return NGX_ERROR;
498     }
499 
500     if (n > 0) {
501         s->buffer->last += n;
502     }
503 
504     if (n == NGX_AGAIN) {
505         if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) {
506             ngx_mail_session_internal_server_error(s);
507             return NGX_ERROR;
508         }
509 
510         return NGX_AGAIN;
511     }
512 
513     ngx_mail_smtp_log_rejected_command(s, c, err);
514 
515     s->buffer->pos = s->buffer->start;
516     s->buffer->last = s->buffer->start;
517 
518     return NGX_OK;
519 }
520 
521 
522 static void
523 ngx_mail_smtp_log_rejected_command(ngx_mail_session_t *s, ngx_connection_t *c,
524     char *err)
525 {
526     u_char      ch;
527     ngx_str_t   cmd;
528     ngx_uint_t  i;
529 
530     if (c->log->log_level < NGX_LOG_INFO) {
531         return;
532     }
533 
534     cmd.len = s->buffer->last - s->buffer->start;
535     cmd.data = s->buffer->start;
536 
537     for (i = 0; i < cmd.len; i++) {
538         ch = cmd.data[i];
539 
540         if (ch != CR && ch != LF) {
541             continue;
542         }
543 
544         cmd.data[i] = '_';
545     }
546 
547     cmd.len = i;
548 
549     ngx_log_error(NGX_LOG_INFO, c->log, 0, err, &cmd);
550 }
551 

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