Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.15.11 ]​[ nginx-1.14.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_pop3_module.h>
0013 
0014 
0015 static ngx_int_t ngx_mail_pop3_user(ngx_mail_session_t *s, ngx_connection_t *c);
0016 static ngx_int_t ngx_mail_pop3_pass(ngx_mail_session_t *s, ngx_connection_t *c);
0017 static ngx_int_t ngx_mail_pop3_capa(ngx_mail_session_t *s, ngx_connection_t *c,
0018     ngx_int_t stls);
0019 static ngx_int_t ngx_mail_pop3_stls(ngx_mail_session_t *s, ngx_connection_t *c);
0020 static ngx_int_t ngx_mail_pop3_apop(ngx_mail_session_t *s, ngx_connection_t *c);
0021 static ngx_int_t ngx_mail_pop3_auth(ngx_mail_session_t *s, ngx_connection_t *c);
0022 
0023 
0024 static u_char  pop3_greeting[] = "+OK POP3 ready" CRLF;
0025 static u_char  pop3_ok[] = "+OK" CRLF;
0026 static u_char  pop3_next[] = "+ " CRLF;
0027 static u_char  pop3_username[] = "+ VXNlcm5hbWU6" CRLF;
0028 static u_char  pop3_password[] = "+ UGFzc3dvcmQ6" CRLF;
0029 static u_char  pop3_invalid_command[] = "-ERR invalid command" CRLF;
0030 
0031 
0032 void
0033 ngx_mail_pop3_init_session(ngx_mail_session_t *s, ngx_connection_t *c)
0034 {
0035     u_char                    *p;
0036     ngx_mail_core_srv_conf_t  *cscf;
0037     ngx_mail_pop3_srv_conf_t  *pscf;
0038 
0039     pscf = ngx_mail_get_module_srv_conf(s, ngx_mail_pop3_module);
0040     cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
0041 
0042     if (pscf->auth_methods
0043         & (NGX_MAIL_AUTH_APOP_ENABLED|NGX_MAIL_AUTH_CRAM_MD5_ENABLED))
0044     {
0045         if (ngx_mail_salt(s, c, cscf) != NGX_OK) {
0046             ngx_mail_session_internal_server_error(s);
0047             return;
0048         }
0049 
0050         s->out.data = ngx_pnalloc(c->pool, sizeof(pop3_greeting) + s->salt.len);
0051         if (s->out.data == NULL) {
0052             ngx_mail_session_internal_server_error(s);
0053             return;
0054         }
0055 
0056         p = ngx_cpymem(s->out.data, pop3_greeting, sizeof(pop3_greeting) - 3);
0057         *p++ = ' ';
0058         p = ngx_cpymem(p, s->salt.data, s->salt.len);
0059 
0060         s->out.len = p - s->out.data;
0061 
0062     } else {
0063         ngx_str_set(&s->out, pop3_greeting);
0064     }
0065 
0066     c->read->handler = ngx_mail_pop3_init_protocol;
0067 
0068     ngx_add_timer(c->read, cscf->timeout);
0069 
0070     if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
0071         ngx_mail_close_connection(c);
0072     }
0073 
0074     ngx_mail_send(c->write);
0075 }
0076 
0077 
0078 void
0079 ngx_mail_pop3_init_protocol(ngx_event_t *rev)
0080 {
0081     ngx_connection_t    *c;
0082     ngx_mail_session_t  *s;
0083 
0084     c = rev->data;
0085 
0086     c->log->action = "in auth state";
0087 
0088     if (rev->timedout) {
0089         ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
0090         c->timedout = 1;
0091         ngx_mail_close_connection(c);
0092         return;
0093     }
0094 
0095     s = c->data;
0096 
0097     if (s->buffer == NULL) {
0098         if (ngx_array_init(&s->args, c->pool, 2, sizeof(ngx_str_t))
0099             == NGX_ERROR)
0100         {
0101             ngx_mail_session_internal_server_error(s);
0102             return;
0103         }
0104 
0105         s->buffer = ngx_create_temp_buf(c->pool, 128);
0106         if (s->buffer == NULL) {
0107             ngx_mail_session_internal_server_error(s);
0108             return;
0109         }
0110     }
0111 
0112     s->mail_state = ngx_pop3_start;
0113     c->read->handler = ngx_mail_pop3_auth_state;
0114 
0115     ngx_mail_pop3_auth_state(rev);
0116 }
0117 
0118 
0119 void
0120 ngx_mail_pop3_auth_state(ngx_event_t *rev)
0121 {
0122     ngx_int_t            rc;
0123     ngx_connection_t    *c;
0124     ngx_mail_session_t  *s;
0125 
0126     c = rev->data;
0127     s = c->data;
0128 
0129     ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "pop3 auth state");
0130 
0131     if (rev->timedout) {
0132         ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
0133         c->timedout = 1;
0134         ngx_mail_close_connection(c);
0135         return;
0136     }
0137 
0138     if (s->out.len) {
0139         ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "pop3 send handler busy");
0140         s->blocked = 1;
0141         return;
0142     }
0143 
0144     s->blocked = 0;
0145 
0146     rc = ngx_mail_read_command(s, c);
0147 
0148     if (rc == NGX_AGAIN || rc == NGX_ERROR) {
0149         return;
0150     }
0151 
0152     ngx_str_set(&s->out, pop3_ok);
0153 
0154     if (rc == NGX_OK) {
0155         switch (s->mail_state) {
0156 
0157         case ngx_pop3_start:
0158 
0159             switch (s->command) {
0160 
0161             case NGX_POP3_USER:
0162                 rc = ngx_mail_pop3_user(s, c);
0163                 break;
0164 
0165             case NGX_POP3_CAPA:
0166                 rc = ngx_mail_pop3_capa(s, c, 1);
0167                 break;
0168 
0169             case NGX_POP3_APOP:
0170                 rc = ngx_mail_pop3_apop(s, c);
0171                 break;
0172 
0173             case NGX_POP3_AUTH:
0174                 rc = ngx_mail_pop3_auth(s, c);
0175                 break;
0176 
0177             case NGX_POP3_QUIT:
0178                 s->quit = 1;
0179                 break;
0180 
0181             case NGX_POP3_NOOP:
0182                 break;
0183 
0184             case NGX_POP3_STLS:
0185                 rc = ngx_mail_pop3_stls(s, c);
0186                 break;
0187 
0188             default:
0189                 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
0190                 break;
0191             }
0192 
0193             break;
0194 
0195         case ngx_pop3_user:
0196 
0197             switch (s->command) {
0198 
0199             case NGX_POP3_PASS:
0200                 rc = ngx_mail_pop3_pass(s, c);
0201                 break;
0202 
0203             case NGX_POP3_CAPA:
0204                 rc = ngx_mail_pop3_capa(s, c, 0);
0205                 break;
0206 
0207             case NGX_POP3_QUIT:
0208                 s->quit = 1;
0209                 break;
0210 
0211             case NGX_POP3_NOOP:
0212                 break;
0213 
0214             default:
0215                 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
0216                 break;
0217             }
0218 
0219             break;
0220 
0221         /* suppress warnings */
0222         case ngx_pop3_passwd:
0223             break;
0224 
0225         case ngx_pop3_auth_login_username:
0226             rc = ngx_mail_auth_login_username(s, c, 0);
0227 
0228             ngx_str_set(&s->out, pop3_password);
0229             s->mail_state = ngx_pop3_auth_login_password;
0230             break;
0231 
0232         case ngx_pop3_auth_login_password:
0233             rc = ngx_mail_auth_login_password(s, c);
0234             break;
0235 
0236         case ngx_pop3_auth_plain:
0237             rc = ngx_mail_auth_plain(s, c, 0);
0238             break;
0239 
0240         case ngx_pop3_auth_cram_md5:
0241             rc = ngx_mail_auth_cram_md5(s, c);
0242             break;
0243 
0244         case ngx_pop3_auth_external:
0245             rc = ngx_mail_auth_external(s, c, 0);
0246             break;
0247         }
0248     }
0249 
0250     switch (rc) {
0251 
0252     case NGX_DONE:
0253         ngx_mail_auth(s, c);
0254         return;
0255 
0256     case NGX_ERROR:
0257         ngx_mail_session_internal_server_error(s);
0258         return;
0259 
0260     case NGX_MAIL_PARSE_INVALID_COMMAND:
0261         s->mail_state = ngx_pop3_start;
0262         s->state = 0;
0263 
0264         ngx_str_set(&s->out, pop3_invalid_command);
0265 
0266         /* fall through */
0267 
0268     case NGX_OK:
0269 
0270         s->args.nelts = 0;
0271         s->buffer->pos = s->buffer->start;
0272         s->buffer->last = s->buffer->start;
0273 
0274         if (s->state) {
0275             s->arg_start = s->buffer->start;
0276         }
0277 
0278         ngx_mail_send(c->write);
0279     }
0280 }
0281 
0282 static ngx_int_t
0283 ngx_mail_pop3_user(ngx_mail_session_t *s, ngx_connection_t *c)
0284 {
0285     ngx_str_t  *arg;
0286 
0287 #if (NGX_MAIL_SSL)
0288     if (ngx_mail_starttls_only(s, c)) {
0289         return NGX_MAIL_PARSE_INVALID_COMMAND;
0290     }
0291 #endif
0292 
0293     if (s->args.nelts != 1) {
0294         return NGX_MAIL_PARSE_INVALID_COMMAND;
0295     }
0296 
0297     arg = s->args.elts;
0298     s->login.len = arg[0].len;
0299     s->login.data = ngx_pnalloc(c->pool, s->login.len);
0300     if (s->login.data == NULL) {
0301         return NGX_ERROR;
0302     }
0303 
0304     ngx_memcpy(s->login.data, arg[0].data, s->login.len);
0305 
0306     ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
0307                    "pop3 login: \"%V\"", &s->login);
0308 
0309     s->mail_state = ngx_pop3_user;
0310 
0311     return NGX_OK;
0312 }
0313 
0314 
0315 static ngx_int_t
0316 ngx_mail_pop3_pass(ngx_mail_session_t *s, ngx_connection_t *c)
0317 {
0318     ngx_str_t  *arg;
0319 
0320     if (s->args.nelts != 1) {
0321         return NGX_MAIL_PARSE_INVALID_COMMAND;
0322     }
0323 
0324     arg = s->args.elts;
0325     s->passwd.len = arg[0].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[0].data, s->passwd.len);
0332 
0333 #if (NGX_DEBUG_MAIL_PASSWD)
0334     ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
0335                    "pop3 passwd: \"%V\"", &s->passwd);
0336 #endif
0337 
0338     return NGX_DONE;
0339 }
0340 
0341 
0342 static ngx_int_t
0343 ngx_mail_pop3_capa(ngx_mail_session_t *s, ngx_connection_t *c, ngx_int_t stls)
0344 {
0345     ngx_mail_pop3_srv_conf_t  *pscf;
0346 
0347     pscf = ngx_mail_get_module_srv_conf(s, ngx_mail_pop3_module);
0348 
0349 #if (NGX_MAIL_SSL)
0350 
0351     if (stls && c->ssl == NULL) {
0352         ngx_mail_ssl_conf_t  *sslcf;
0353 
0354         sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
0355 
0356         if (sslcf->starttls == NGX_MAIL_STARTTLS_ON) {
0357             s->out = pscf->starttls_capability;
0358             return NGX_OK;
0359         }
0360 
0361         if (sslcf->starttls == NGX_MAIL_STARTTLS_ONLY) {
0362             s->out = pscf->starttls_only_capability;
0363             return NGX_OK;
0364         }
0365     }
0366 
0367 #endif
0368 
0369     s->out = pscf->capability;
0370     return NGX_OK;
0371 }
0372 
0373 
0374 static ngx_int_t
0375 ngx_mail_pop3_stls(ngx_mail_session_t *s, ngx_connection_t *c)
0376 {
0377 #if (NGX_MAIL_SSL)
0378     ngx_mail_ssl_conf_t  *sslcf;
0379 
0380     if (c->ssl == NULL) {
0381         sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
0382         if (sslcf->starttls) {
0383             c->read->handler = ngx_mail_starttls_handler;
0384             return NGX_OK;
0385         }
0386     }
0387 
0388 #endif
0389 
0390     return NGX_MAIL_PARSE_INVALID_COMMAND;
0391 }
0392 
0393 
0394 static ngx_int_t
0395 ngx_mail_pop3_apop(ngx_mail_session_t *s, ngx_connection_t *c)
0396 {
0397     ngx_str_t                 *arg;
0398     ngx_mail_pop3_srv_conf_t  *pscf;
0399 
0400 #if (NGX_MAIL_SSL)
0401     if (ngx_mail_starttls_only(s, c)) {
0402         return NGX_MAIL_PARSE_INVALID_COMMAND;
0403     }
0404 #endif
0405 
0406     if (s->args.nelts != 2) {
0407         return NGX_MAIL_PARSE_INVALID_COMMAND;
0408     }
0409 
0410     pscf = ngx_mail_get_module_srv_conf(s, ngx_mail_pop3_module);
0411 
0412     if (!(pscf->auth_methods & NGX_MAIL_AUTH_APOP_ENABLED)) {
0413         return NGX_MAIL_PARSE_INVALID_COMMAND;
0414     }
0415 
0416     arg = s->args.elts;
0417 
0418     s->login.len = arg[0].len;
0419     s->login.data = ngx_pnalloc(c->pool, s->login.len);
0420     if (s->login.data == NULL) {
0421         return NGX_ERROR;
0422     }
0423 
0424     ngx_memcpy(s->login.data, arg[0].data, s->login.len);
0425 
0426     s->passwd.len = arg[1].len;
0427     s->passwd.data = ngx_pnalloc(c->pool, s->passwd.len);
0428     if (s->passwd.data == NULL) {
0429         return NGX_ERROR;
0430     }
0431 
0432     ngx_memcpy(s->passwd.data, arg[1].data, s->passwd.len);
0433 
0434     ngx_log_debug2(NGX_LOG_DEBUG_MAIL, c->log, 0,
0435                    "pop3 apop: \"%V\" \"%V\"", &s->login, &s->passwd);
0436 
0437     s->auth_method = NGX_MAIL_AUTH_APOP;
0438 
0439     return NGX_DONE;
0440 }
0441 
0442 
0443 static ngx_int_t
0444 ngx_mail_pop3_auth(ngx_mail_session_t *s, ngx_connection_t *c)
0445 {
0446     ngx_int_t                  rc;
0447     ngx_mail_pop3_srv_conf_t  *pscf;
0448 
0449 #if (NGX_MAIL_SSL)
0450     if (ngx_mail_starttls_only(s, c)) {
0451         return NGX_MAIL_PARSE_INVALID_COMMAND;
0452     }
0453 #endif
0454 
0455     pscf = ngx_mail_get_module_srv_conf(s, ngx_mail_pop3_module);
0456 
0457     if (s->args.nelts == 0) {
0458         s->out = pscf->auth_capability;
0459         s->state = 0;
0460 
0461         return NGX_OK;
0462     }
0463 
0464     rc = ngx_mail_auth_parse(s, c);
0465 
0466     switch (rc) {
0467 
0468     case NGX_MAIL_AUTH_LOGIN:
0469 
0470         ngx_str_set(&s->out, pop3_username);
0471         s->mail_state = ngx_pop3_auth_login_username;
0472 
0473         return NGX_OK;
0474 
0475     case NGX_MAIL_AUTH_LOGIN_USERNAME:
0476 
0477         ngx_str_set(&s->out, pop3_password);
0478         s->mail_state = ngx_pop3_auth_login_password;
0479 
0480         return ngx_mail_auth_login_username(s, c, 1);
0481 
0482     case NGX_MAIL_AUTH_PLAIN:
0483 
0484         ngx_str_set(&s->out, pop3_next);
0485         s->mail_state = ngx_pop3_auth_plain;
0486 
0487         return NGX_OK;
0488 
0489     case NGX_MAIL_AUTH_CRAM_MD5:
0490 
0491         if (!(pscf->auth_methods & NGX_MAIL_AUTH_CRAM_MD5_ENABLED)) {
0492             return NGX_MAIL_PARSE_INVALID_COMMAND;
0493         }
0494 
0495         if (ngx_mail_auth_cram_md5_salt(s, c, "+ ", 2) == NGX_OK) {
0496             s->mail_state = ngx_pop3_auth_cram_md5;
0497             return NGX_OK;
0498         }
0499 
0500         return NGX_ERROR;
0501 
0502     case NGX_MAIL_AUTH_EXTERNAL:
0503 
0504         if (!(pscf->auth_methods & NGX_MAIL_AUTH_EXTERNAL_ENABLED)) {
0505             return NGX_MAIL_PARSE_INVALID_COMMAND;
0506         }
0507 
0508         ngx_str_set(&s->out, pop3_username);
0509         s->mail_state = ngx_pop3_auth_external;
0510 
0511         return NGX_OK;
0512     }
0513 
0514     return rc;
0515 }