Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.13.12 ]​[ nginx-1.12.2 ]​

0001 
0002 /*
0003  * Copyright (C) Igor Sysoev
0004  * Copyright (C) Nginx, Inc.
0005  */
0006 
0007 
0008 #include <ngx_config.h>
0009 #include <ngx_core.h>
0010 #include <ngx_event.h>
0011 #include <ngx_mail.h>
0012 #include <ngx_mail_imap_module.h>
0013 
0014 
0015 static ngx_int_t ngx_mail_imap_login(ngx_mail_session_t *s,
0016     ngx_connection_t *c);
0017 static ngx_int_t ngx_mail_imap_authenticate(ngx_mail_session_t *s,
0018     ngx_connection_t *c);
0019 static ngx_int_t ngx_mail_imap_capability(ngx_mail_session_t *s,
0020     ngx_connection_t *c);
0021 static ngx_int_t ngx_mail_imap_starttls(ngx_mail_session_t *s,
0022     ngx_connection_t *c);
0023 
0024 
0025 static u_char  imap_greeting[] = "* OK IMAP4 ready" CRLF;
0026 static u_char  imap_star[] = "* ";
0027 static u_char  imap_ok[] = "OK completed" CRLF;
0028 static u_char  imap_next[] = "+ OK" CRLF;
0029 static u_char  imap_plain_next[] = "+ " CRLF;
0030 static u_char  imap_username[] = "+ VXNlcm5hbWU6" CRLF;
0031 static u_char  imap_password[] = "+ UGFzc3dvcmQ6" CRLF;
0032 static u_char  imap_bye[] = "* BYE" CRLF;
0033 static u_char  imap_invalid_command[] = "BAD invalid command" CRLF;
0034 
0035 
0036 void
0037 ngx_mail_imap_init_session(ngx_mail_session_t *s, ngx_connection_t *c)
0038 {
0039     ngx_mail_core_srv_conf_t  *cscf;
0040 
0041     cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
0042 
0043     ngx_str_set(&s->out, imap_greeting);
0044 
0045     c->read->handler = ngx_mail_imap_init_protocol;
0046 
0047     ngx_add_timer(c->read, cscf->timeout);
0048 
0049     if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
0050         ngx_mail_close_connection(c);
0051     }
0052 
0053     ngx_mail_send(c->write);
0054 }
0055 
0056 
0057 void
0058 ngx_mail_imap_init_protocol(ngx_event_t *rev)
0059 {
0060     ngx_connection_t          *c;
0061     ngx_mail_session_t        *s;
0062     ngx_mail_imap_srv_conf_t  *iscf;
0063 
0064     c = rev->data;
0065 
0066     c->log->action = "in auth state";
0067 
0068     if (rev->timedout) {
0069         ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
0070         c->timedout = 1;
0071         ngx_mail_close_connection(c);
0072         return;
0073     }
0074 
0075     s = c->data;
0076 
0077     if (s->buffer == NULL) {
0078         if (ngx_array_init(&s->args, c->pool, 2, sizeof(ngx_str_t))
0079             == NGX_ERROR)
0080         {
0081             ngx_mail_session_internal_server_error(s);
0082             return;
0083         }
0084 
0085         iscf = ngx_mail_get_module_srv_conf(s, ngx_mail_imap_module);
0086 
0087         s->buffer = ngx_create_temp_buf(c->pool, iscf->client_buffer_size);
0088         if (s->buffer == NULL) {
0089             ngx_mail_session_internal_server_error(s);
0090             return;
0091         }
0092     }
0093 
0094     s->mail_state = ngx_imap_start;
0095     c->read->handler = ngx_mail_imap_auth_state;
0096 
0097     ngx_mail_imap_auth_state(rev);
0098 }
0099 
0100 
0101 void
0102 ngx_mail_imap_auth_state(ngx_event_t *rev)
0103 {
0104     u_char              *p, *dst, *src, *end;
0105     ngx_str_t           *arg;
0106     ngx_int_t            rc;
0107     ngx_uint_t           tag, i;
0108     ngx_connection_t    *c;
0109     ngx_mail_session_t  *s;
0110 
0111     c = rev->data;
0112     s = c->data;
0113 
0114     ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "imap auth state");
0115 
0116     if (rev->timedout) {
0117         ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
0118         c->timedout = 1;
0119         ngx_mail_close_connection(c);
0120         return;
0121     }
0122 
0123     if (s->out.len) {
0124         ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "imap send handler busy");
0125         s->blocked = 1;
0126         return;
0127     }
0128 
0129     s->blocked = 0;
0130 
0131     rc = ngx_mail_read_command(s, c);
0132 
0133     if (rc == NGX_AGAIN || rc == NGX_ERROR) {
0134         return;
0135     }
0136 
0137     tag = 1;
0138     s->text.len = 0;
0139     ngx_str_set(&s->out, imap_ok);
0140 
0141     if (rc == NGX_OK) {
0142 
0143         ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0, "imap auth command: %i",
0144                        s->command);
0145 
0146         if (s->backslash) {
0147 
0148             arg = s->args.elts;
0149 
0150             for (i = 0; i < s->args.nelts; i++) {
0151                 dst = arg[i].data;
0152                 end = dst + arg[i].len;
0153 
0154                 for (src = dst; src < end; dst++) {
0155                     *dst = *src;
0156                     if (*src++ == '\\') {
0157                         *dst = *src++;
0158                     }
0159                 }
0160 
0161                 arg[i].len = dst - arg[i].data;
0162             }
0163 
0164             s->backslash = 0;
0165         }
0166 
0167         switch (s->mail_state) {
0168 
0169         case ngx_imap_start:
0170 
0171             switch (s->command) {
0172 
0173             case NGX_IMAP_LOGIN:
0174                 rc = ngx_mail_imap_login(s, c);
0175                 break;
0176 
0177             case NGX_IMAP_AUTHENTICATE:
0178                 rc = ngx_mail_imap_authenticate(s, c);
0179                 tag = (rc != NGX_OK);
0180                 break;
0181 
0182             case NGX_IMAP_CAPABILITY:
0183                 rc = ngx_mail_imap_capability(s, c);
0184                 break;
0185 
0186             case NGX_IMAP_LOGOUT:
0187                 s->quit = 1;
0188                 ngx_str_set(&s->text, imap_bye);
0189                 break;
0190 
0191             case NGX_IMAP_NOOP:
0192                 break;
0193 
0194             case NGX_IMAP_STARTTLS:
0195                 rc = ngx_mail_imap_starttls(s, c);
0196                 break;
0197 
0198             default:
0199                 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
0200                 break;
0201             }
0202 
0203             break;
0204 
0205         case ngx_imap_auth_login_username:
0206             rc = ngx_mail_auth_login_username(s, c, 0);
0207 
0208             tag = 0;
0209             ngx_str_set(&s->out, imap_password);
0210             s->mail_state = ngx_imap_auth_login_password;
0211 
0212             break;
0213 
0214         case ngx_imap_auth_login_password:
0215             rc = ngx_mail_auth_login_password(s, c);
0216             break;
0217 
0218         case ngx_imap_auth_plain:
0219             rc = ngx_mail_auth_plain(s, c, 0);
0220             break;
0221 
0222         case ngx_imap_auth_cram_md5:
0223             rc = ngx_mail_auth_cram_md5(s, c);
0224             break;
0225 
0226         case ngx_imap_auth_external:
0227             rc = ngx_mail_auth_external(s, c, 0);
0228             break;
0229         }
0230 
0231     } else if (rc == NGX_IMAP_NEXT) {
0232         tag = 0;
0233         ngx_str_set(&s->out, imap_next);
0234     }
0235 
0236     switch (rc) {
0237 
0238     case NGX_DONE:
0239         ngx_mail_auth(s, c);
0240         return;
0241 
0242     case NGX_ERROR:
0243         ngx_mail_session_internal_server_error(s);
0244         return;
0245 
0246     case NGX_MAIL_PARSE_INVALID_COMMAND:
0247         s->state = 0;
0248         ngx_str_set(&s->out, imap_invalid_command);
0249         s->mail_state = ngx_imap_start;
0250         break;
0251     }
0252 
0253     if (tag) {
0254         if (s->tag.len == 0) {
0255             ngx_str_set(&s->tag, imap_star);
0256         }
0257 
0258         if (s->tagged_line.len < s->tag.len + s->text.len + s->out.len) {
0259             s->tagged_line.len = s->tag.len + s->text.len + s->out.len;
0260             s->tagged_line.data = ngx_pnalloc(c->pool, s->tagged_line.len);
0261             if (s->tagged_line.data == NULL) {
0262                 ngx_mail_close_connection(c);
0263                 return;
0264             }
0265         }
0266 
0267         p = s->tagged_line.data;
0268 
0269         if (s->text.len) {
0270             p = ngx_cpymem(p, s->text.data, s->text.len);
0271         }
0272 
0273         p = ngx_cpymem(p, s->tag.data, s->tag.len);
0274         ngx_memcpy(p, s->out.data, s->out.len);
0275 
0276         s->out.len = s->text.len + s->tag.len + s->out.len;
0277         s->out.data = s->tagged_line.data;
0278     }
0279 
0280     if (rc != NGX_IMAP_NEXT) {
0281         s->args.nelts = 0;
0282 
0283         if (s->state) {
0284             /* preserve tag */
0285             s->arg_start = s->buffer->start + s->tag.len;
0286             s->buffer->pos = s->arg_start;
0287             s->buffer->last = s->arg_start;
0288 
0289         } else {
0290             s->buffer->pos = s->buffer->start;
0291             s->buffer->last = s->buffer->start;
0292             s->tag.len = 0;
0293         }
0294     }
0295 
0296     ngx_mail_send(c->write);
0297 }
0298 
0299 
0300 static ngx_int_t
0301 ngx_mail_imap_login(ngx_mail_session_t *s, ngx_connection_t *c)
0302 {
0303     ngx_str_t  *arg;
0304 
0305 #if (NGX_MAIL_SSL)
0306     if (ngx_mail_starttls_only(s, c)) {
0307         return NGX_MAIL_PARSE_INVALID_COMMAND;
0308     }
0309 #endif
0310 
0311     arg = s->args.elts;
0312 
0313     if (s->args.nelts != 2 || arg[0].len == 0) {
0314         return NGX_MAIL_PARSE_INVALID_COMMAND;
0315     }
0316 
0317     s->login.len = arg[0].len;
0318     s->login.data = ngx_pnalloc(c->pool, s->login.len);
0319     if (s->login.data == NULL) {
0320         return NGX_ERROR;
0321     }
0322 
0323     ngx_memcpy(s->login.data, arg[0].data, s->login.len);
0324 
0325     s->passwd.len = arg[1].len;
0326     s->passwd.data = ngx_pnalloc(c->pool, s->passwd.len);
0327     if (s->passwd.data == NULL) {
0328         return NGX_ERROR;
0329     }
0330 
0331     ngx_memcpy(s->passwd.data, arg[1].data, s->passwd.len);
0332 
0333 #if (NGX_DEBUG_MAIL_PASSWD)
0334     ngx_log_debug2(NGX_LOG_DEBUG_MAIL, c->log, 0,
0335                    "imap login:\"%V\" passwd:\"%V\"",
0336                    &s->login, &s->passwd);
0337 #else
0338     ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
0339                    "imap login:\"%V\"", &s->login);
0340 #endif
0341 
0342     return NGX_DONE;
0343 }
0344 
0345 
0346 static ngx_int_t
0347 ngx_mail_imap_authenticate(ngx_mail_session_t *s, ngx_connection_t *c)
0348 {
0349     ngx_int_t                  rc;
0350     ngx_mail_core_srv_conf_t  *cscf;
0351     ngx_mail_imap_srv_conf_t  *iscf;
0352 
0353 #if (NGX_MAIL_SSL)
0354     if (ngx_mail_starttls_only(s, c)) {
0355         return NGX_MAIL_PARSE_INVALID_COMMAND;
0356     }
0357 #endif
0358 
0359     iscf = ngx_mail_get_module_srv_conf(s, ngx_mail_imap_module);
0360 
0361     rc = ngx_mail_auth_parse(s, c);
0362 
0363     switch (rc) {
0364 
0365     case NGX_MAIL_AUTH_LOGIN:
0366 
0367         ngx_str_set(&s->out, imap_username);
0368         s->mail_state = ngx_imap_auth_login_username;
0369 
0370         return NGX_OK;
0371 
0372     case NGX_MAIL_AUTH_LOGIN_USERNAME:
0373 
0374         ngx_str_set(&s->out, imap_password);
0375         s->mail_state = ngx_imap_auth_login_password;
0376 
0377         return ngx_mail_auth_login_username(s, c, 1);
0378 
0379     case NGX_MAIL_AUTH_PLAIN:
0380 
0381         ngx_str_set(&s->out, imap_plain_next);
0382         s->mail_state = ngx_imap_auth_plain;
0383 
0384         return NGX_OK;
0385 
0386     case NGX_MAIL_AUTH_CRAM_MD5:
0387 
0388         if (!(iscf->auth_methods & NGX_MAIL_AUTH_CRAM_MD5_ENABLED)) {
0389             return NGX_MAIL_PARSE_INVALID_COMMAND;
0390         }
0391 
0392         if (s->salt.data == NULL) {
0393             cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
0394 
0395             if (ngx_mail_salt(s, c, cscf) != NGX_OK) {
0396                 return NGX_ERROR;
0397             }
0398         }
0399 
0400         if (ngx_mail_auth_cram_md5_salt(s, c, "+ ", 2) == NGX_OK) {
0401             s->mail_state = ngx_imap_auth_cram_md5;
0402             return NGX_OK;
0403         }
0404 
0405         return NGX_ERROR;
0406 
0407     case NGX_MAIL_AUTH_EXTERNAL:
0408 
0409         if (!(iscf->auth_methods & NGX_MAIL_AUTH_EXTERNAL_ENABLED)) {
0410             return NGX_MAIL_PARSE_INVALID_COMMAND;
0411         }
0412 
0413         ngx_str_set(&s->out, imap_username);
0414         s->mail_state = ngx_imap_auth_external;
0415 
0416         return NGX_OK;
0417     }
0418 
0419     return rc;
0420 }
0421 
0422 
0423 static ngx_int_t
0424 ngx_mail_imap_capability(ngx_mail_session_t *s, ngx_connection_t *c)
0425 {
0426     ngx_mail_imap_srv_conf_t  *iscf;
0427 
0428     iscf = ngx_mail_get_module_srv_conf(s, ngx_mail_imap_module);
0429 
0430 #if (NGX_MAIL_SSL)
0431 
0432     if (c->ssl == NULL) {
0433         ngx_mail_ssl_conf_t  *sslcf;
0434 
0435         sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
0436 
0437         if (sslcf->starttls == NGX_MAIL_STARTTLS_ON) {
0438             s->text = iscf->starttls_capability;
0439             return NGX_OK;
0440         }
0441 
0442         if (sslcf->starttls == NGX_MAIL_STARTTLS_ONLY) {
0443             s->text = iscf->starttls_only_capability;
0444             return NGX_OK;
0445         }
0446     }
0447 #endif
0448 
0449     s->text = iscf->capability;
0450 
0451     return NGX_OK;
0452 }
0453 
0454 
0455 static ngx_int_t
0456 ngx_mail_imap_starttls(ngx_mail_session_t *s, ngx_connection_t *c)
0457 {
0458 #if (NGX_MAIL_SSL)
0459     ngx_mail_ssl_conf_t  *sslcf;
0460 
0461     if (c->ssl == NULL) {
0462         sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
0463         if (sslcf->starttls) {
0464             c->read->handler = ngx_mail_starttls_handler;
0465             return NGX_OK;
0466         }
0467     }
0468 
0469 #endif
0470 
0471     return NGX_MAIL_PARSE_INVALID_COMMAND;
0472 }