コード例 #1
0
ngx_int_t
ngx_mail_auth_parse(ngx_mail_session_t *s, ngx_connection_t *c)
{
    ngx_str_t                 *arg;

#if (NGX_MAIL_SSL)
    if (ngx_mail_starttls_only(s, c)) {
        return NGX_MAIL_PARSE_INVALID_COMMAND;
    }
#endif

    arg = s->args.elts;

    if (arg[0].len == 5) {

        if (ngx_strncasecmp(arg[0].data, (u_char *) "LOGIN", 5) == 0) {

            if (s->args.nelts == 1) {
                return NGX_MAIL_AUTH_LOGIN;
            }

            if (s->args.nelts == 2) {
                return NGX_MAIL_AUTH_LOGIN_USERNAME;
            }

            return NGX_MAIL_PARSE_INVALID_COMMAND;
        }

        if (ngx_strncasecmp(arg[0].data, (u_char *) "PLAIN", 5) == 0) {

            if (s->args.nelts == 1) {
                return NGX_MAIL_AUTH_PLAIN;
            }

            if (s->args.nelts == 2) {
                return ngx_mail_auth_plain(s, c, 1);
            }
        }

        return NGX_MAIL_PARSE_INVALID_COMMAND;
    }

    if (arg[0].len == 8) {

        if (s->args.nelts != 1) {
            return NGX_MAIL_PARSE_INVALID_COMMAND;
        }

        if (ngx_strncasecmp(arg[0].data, (u_char *) "CRAM-MD5", 8) == 0) {
            return NGX_MAIL_AUTH_CRAM_MD5;
        }
    }

    return NGX_MAIL_PARSE_INVALID_COMMAND;
}
コード例 #2
0
static ngx_int_t
ngx_mail_imap_authenticate(ngx_mail_session_t *s, ngx_connection_t *c)
{
    ngx_int_t                  rc, res;
    ngx_mail_core_srv_conf_t  *cscf;
    ngx_mail_imap_srv_conf_t  *iscf;

    rc = ngx_mail_auth_parse(s, c);
    iscf = ngx_mail_get_module_srv_conf(s, ngx_mail_imap_module);

    switch (rc) {

    case NGX_MAIL_AUTH_LOGIN:
        if (!(iscf->auth_methods & NGX_MAIL_AUTH_LOGIN_ENABLED)) {
            return NGX_MAIL_PARSE_INVALID_AUTH_MECH;
        }
        ngx_str_set(&s->out, imap_username);
        s->mail_state = ngx_imap_auth_login_username;

        return NGX_MAIL_AUTH_ARGUMENT;

    case NGX_MAIL_AUTH_LOGIN_USERNAME:
        if (!(iscf->auth_methods & NGX_MAIL_AUTH_LOGIN_ENABLED)) {
            return NGX_MAIL_PARSE_INVALID_AUTH_MECH;
        }

        res = ngx_mail_auth_login_username(s, c, 1);
        if (res == NGX_MAIL_AUTH_ARGUMENT) {
            ngx_str_set(&s->out, imap_password);
            s->mail_state = ngx_imap_auth_login_password;
            return NGX_MAIL_AUTH_ARGUMENT;
        } else {
            return res;
        }

    case NGX_MAIL_AUTH_PLAIN:
        if (!(iscf->auth_methods & NGX_MAIL_AUTH_PLAIN_ENABLED)) {
            return NGX_MAIL_PARSE_INVALID_AUTH_MECH;
        }
        ngx_str_set(&s->out, imap_plain_next);
        s->mail_state = ngx_imap_auth_plain;

        return NGX_MAIL_AUTH_ARGUMENT;

    case NGX_MAIL_AUTH_PLAIN_IR:
        if (!(iscf->auth_methods & NGX_MAIL_AUTH_PLAIN_ENABLED)) {
            return NGX_MAIL_PARSE_INVALID_AUTH_MECH;
        }
        return ngx_mail_auth_plain(s, c, 1);

    case NGX_MAIL_AUTH_GSSAPI:
        if (!(iscf->auth_methods & NGX_MAIL_AUTH_GSSAPI_ENABLED)) {
            return NGX_MAIL_PARSE_INVALID_AUTH_MECH;
        }
        ngx_str_set(&s->out, imap_gssapi_next);
        s->mail_state = ngx_imap_auth_gssapi;

        return NGX_MAIL_AUTH_ARGUMENT;

    case NGX_MAIL_AUTH_GSSAPI_IR:
        if (!(iscf->auth_methods & NGX_MAIL_AUTH_GSSAPI_ENABLED)) {
            return NGX_MAIL_PARSE_INVALID_AUTH_MECH;
        }
        s->mail_state = ngx_imap_auth_gssapi;
        ngx_str_t output;
        ngx_str_set(&output, "");
        res = ngx_mail_auth_gssapi(s, c, &output);
        if(res == NGX_MAIL_AUTH_ARGUMENT) {
            s->out = output;
            return NGX_MAIL_AUTH_ARGUMENT;
        } else {
            return res;
        }

    case NGX_MAIL_AUTH_CRAM_MD5:
        if (!(iscf->auth_methods & NGX_MAIL_AUTH_CRAM_MD5_ENABLED)) {
            return NGX_MAIL_PARSE_INVALID_AUTH_MECH;
        }

        if (s->salt.data == NULL) {
            cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);

            if (ngx_mail_salt(s, c, cscf) != NGX_OK) {
                return NGX_ERROR;
            }
        }

        if (ngx_mail_auth_cram_md5_salt(s, c, "+ ", 2) == NGX_OK) {
            s->mail_state = ngx_imap_auth_cram_md5;
            return NGX_MAIL_AUTH_ARGUMENT;
        }

        return NGX_ERROR;
    }

    return rc;
}
コード例 #3
0
void
ngx_mail_imap_auth_state(ngx_event_t *rev)
{
    u_char              *p, *dst, *src, *end;
    ngx_str_t           *arg;
    ngx_int_t            rc;
    ngx_uint_t           tag, i;
    ngx_connection_t    *c;
    ngx_mail_session_t  *s;

    c = rev->data;
    s = c->data;

    ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "imap auth state");

    if (rev->timedout) {
        ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
        c->timedout = 1;
        ngx_mail_end_session(s);    /* send IMAP BYE on timeout */
        return;
    }

    if (s->out.len) {
        ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "imap send handler busy");
        s->blocked = 1;
        return;
    }

    s->blocked = 0;

    rc = ngx_mail_read_command(s, c);

    if (rc == NGX_AGAIN || rc == NGX_ERROR) {
        return;
    }

    if (rc == NGX_IMAP_NEXT) {
        tag = 0;
        ngx_str_set(&s->out, imap_next);
    } else {
        tag = 1;
        ngx_str_set(&s->out, imap_ok);
        s->text.len = 0;

        ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0, "imap auth command: %i",
                       s->command);

        if (s->backslash) {

            arg = s->args.elts;

            for (i = 0; i < s->args.nelts; i++) {
                dst = arg[i].data;
                end = dst + arg[i].len;

                for (src = dst; src < end; dst++) {
                    *dst = *src;
                    if (*src++ == '\\') {
                        *dst = *src++;
                    }
                }

                arg[i].len = dst - arg[i].data;
            }

            s->backslash = 0;
        }

        if (rc == NGX_OK) {
            switch (s->mail_state) {

            case ngx_imap_start:

                switch (s->command) {

                case NGX_IMAP_LOGIN:
                      rc = ngx_mail_imap_login(s, c);
                      break;

                case NGX_IMAP_AUTHENTICATE:
                      rc = ngx_mail_imap_authenticate(s, c);
                      break;

                case NGX_IMAP_CAPABILITY:
                      rc = ngx_mail_imap_capability(s, c);
                      break;

                case NGX_IMAP_LOGOUT:
                    s->quit = 1;
                    ngx_str_set(&s->text, imap_bye);
                    break;

                case NGX_IMAP_NOOP:
                    break;

                case NGX_IMAP_STARTTLS:
                    rc = ngx_mail_imap_starttls(s, c);
                    break;

                case NGX_IMAP_ID:
                    rc = ngx_mail_imap_id(s, c);
                    break;

                default:
                    rc = NGX_MAIL_PARSE_INVALID_COMMAND;
                    break;
                }

                break;

            case ngx_imap_auth_login_username:
                rc = ngx_mail_auth_login_username(s, c, 0);
                if (rc == NGX_MAIL_AUTH_ARGUMENT) {
                    ngx_str_set(&s->out, imap_password);
                    s->mail_state = ngx_imap_auth_login_password;
                }

                break;

            case ngx_imap_auth_login_password:
                rc = ngx_mail_auth_login_password(s, c);
                break;

            case ngx_imap_auth_plain:
                rc = ngx_mail_auth_plain(s, c, 0);
                break;

            case ngx_imap_auth_gssapi:
                {
                    ngx_str_t output;
                    ngx_str_set(&output, "");
                    rc = ngx_mail_auth_gssapi(s, c, &output);
                    if (rc == NGX_MAIL_AUTH_ARGUMENT) {
                        s->mail_state = ngx_imap_auth_gssapi;
                        s->out = output;
                    }
                    break;
                }

            case ngx_imap_auth_cram_md5:
                rc = ngx_mail_auth_cram_md5(s, c);
                break;
            }
        }
    }

    switch (rc) {

    case NGX_DONE:
        ngx_mail_do_auth(s, c);
        return;

    case NGX_OK:
        ngx_mail_set_imap_parse_state_start(s);
        s->arg_start = NULL;
        ngx_mail_reset_parse_buffer(s);
        break;

    case NGX_MAIL_AUTH_ABORT:
        ngx_str_set(&s->out, imap_authaborted);
        s->mail_state = ngx_imap_start;
        ngx_mail_set_imap_parse_state_start(s);
        s->arg_start = NULL;
        ngx_mail_reset_parse_buffer(s);
        break;

    case NGX_ERROR:
        ngx_mail_session_internal_server_error(s);
        return;
    case NGX_MAIL_AUTH_FAILED:
        ngx_str_set(&s->out, imap_authenticate_failed);
        s->mail_state = ngx_imap_start;
        ngx_mail_set_imap_parse_state_start(s);
        s->arg_start = NULL;
        ngx_mail_reset_parse_buffer(s);
        break;

    case NGX_MAIL_LOGIN_FAILED:
        ngx_str_set(&s->out, imap_login_failed);
        s->mail_state = ngx_imap_start;
        ngx_mail_set_imap_parse_state_start(s);
        s->arg_start = NULL;
        ngx_mail_reset_parse_buffer(s);
        break;

    case NGX_MAIL_PARSE_INVALID_AUTH_MECH:
        ngx_log_debug0 (NGX_LOG_DEBUG_MAIL, c->log, 0,
            "unsupported IMAP auth mechanism");
        ngx_str_set(&s->out, imap_unsupported_mech);
        s->mail_state = ngx_imap_start;
        ngx_mail_set_imap_parse_state_start(s);
        s->arg_start = NULL;
        ngx_mail_reset_parse_buffer(s);
        break;

    case NGX_MAIL_PARSE_INVALID_COMMAND:
        ngx_str_set(&s->out, imap_invalid_command);
        s->mail_state = ngx_imap_start;
        ngx_mail_set_imap_parse_state_start(s);
        s->arg_start = NULL;
        ngx_mail_reset_parse_buffer(s);
        break;

    case NGX_MAIL_AUTH_ARGUMENT:
        ngx_mail_set_imap_parse_state_argument(s);
        /* preserve tag, since tag's memory is allocated in buffer, need to set the
         * buffer pos after tag */
        s->arg_start = s->buffer->start + s->tag.len;
        s->buffer->pos = s->arg_start;
        s->buffer->last = s->arg_start;
        tag = 0; // just output s->out
        break;

    case NGX_IMAP_NEXT:
        /* do nothing, preserve all the state, including s->state, s->mail_state,
         * , s->buffer, s->arg_start
         */
        break;
    }

    //clear args
    if(rc != NGX_IMAP_NEXT) {
        s->args.nelts = 0;
    }

    // process the output
    if (tag) { //text tag out --> out
        if (s->tag.len == 0) {
            ngx_str_set(&s->tag, imap_star);
        }

        if (s->tagged_line.len < s->tag.len + s->text.len + s->out.len + 1) {
            s->tagged_line.len = s->tag.len + s->text.len + s->out.len + 1;
            s->tagged_line.data = ngx_pnalloc(c->pool, s->tagged_line.len);
            if (s->tagged_line.data == NULL) {
                ngx_mail_close_connection(c);
                return;
            }
        }

        p = s->tagged_line.data;

        if (s->text.len) {
            p = ngx_cpymem(p, s->text.data, s->text.len);
        }

        p = ngx_cpymem(p, s->tag.data, s->tag.len);
        *p++ = ' '; /* the space between tag and out */
        ngx_memcpy(p, s->out.data, s->out.len);

        s->out.len = s->text.len + s->tag.len + 1 /*for space*/+ s->out.len;
        s->out.data = s->tagged_line.data;
    }

    ngx_mail_send(c->write);
}
コード例 #4
0
void
ngx_mail_smtp_auth_state(ngx_event_t *rev)
{
    ngx_int_t            rc;
    ngx_connection_t    *c;
    ngx_mail_session_t  *s;

    c = rev->data;
    s = c->data;

    ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "smtp auth state");

    if (rev->timedout) {
        ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
        c->timedout = 1;
        ngx_mail_close_connection(c);
        return;
    }

    if (s->out.len) {
        ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "smtp send handler busy");
        s->blocked = 1;
        return;
    }

    s->blocked = 0;

    rc = ngx_mail_read_command(s, c);

    if (rc == NGX_AGAIN || rc == NGX_ERROR) {
        return;
    }

    s->out.len = sizeof(smtp_ok) - 1;
    s->out.data = smtp_ok;

    if (rc == NGX_OK) {
        switch (s->mail_state) {

        case ngx_smtp_start:

            switch (s->command) {

            case NGX_SMTP_HELO:
            case NGX_SMTP_EHLO:
                rc = ngx_mail_smtp_helo(s, c);
                break;

            case NGX_SMTP_AUTH:
                rc = ngx_mail_smtp_auth(s, c);
                break;

            case NGX_SMTP_QUIT:
                s->quit = 1;
                s->out.len = sizeof(smtp_bye) - 1;
                s->out.data = smtp_bye;
                break;

            case NGX_SMTP_MAIL:
                rc = ngx_mail_smtp_mail(s, c);
                break;

            case NGX_SMTP_NOOP:
            case NGX_SMTP_RSET:
                break;

            case NGX_SMTP_STARTTLS:
                rc = ngx_mail_smtp_starttls(s, c);
                s->out.len = sizeof(smtp_starttls) - 1;
                s->out.data = smtp_starttls;
                break;

            default:
                rc = NGX_MAIL_PARSE_INVALID_COMMAND;
                break;
            }

            break;

        case ngx_smtp_auth_login_username:
            rc = ngx_mail_auth_login_username(s, c, 0);

            s->out.len = sizeof(smtp_password) - 1;
            s->out.data = smtp_password;
            s->mail_state = ngx_smtp_auth_login_password;
            break;

        case ngx_smtp_auth_login_password:
            rc = ngx_mail_auth_login_password(s, c);
            break;

        case ngx_smtp_auth_plain:
            rc = ngx_mail_auth_plain(s, c, 0);
            break;

        case ngx_smtp_auth_cram_md5:
            rc = ngx_mail_auth_cram_md5(s, c);
            break;
        }
    }

    switch (rc) {

    case NGX_DONE:
        ngx_mail_auth(s, c);
        return;

    case NGX_ERROR:
        ngx_mail_session_internal_server_error(s);
        return;

    case NGX_MAIL_PARSE_INVALID_COMMAND:
        s->mail_state = ngx_smtp_start;
        s->state = 0;

        s->out.len = sizeof(smtp_invalid_command) - 1;
        s->out.data = smtp_invalid_command;

    /* fall through */

    case NGX_OK:
        s->args.nelts = 0;
        s->buffer->pos = s->buffer->start;
        s->buffer->last = s->buffer->start;

        if (s->state) {
            s->arg_start = s->buffer->start;
        }

        ngx_mail_send(c->write);
    }
}
コード例 #5
0
void
ngx_mail_imap_auth_state(ngx_event_t *rev)
{
    u_char              *p, *dst, *src, *end;
    ngx_str_t           *arg;
    ngx_int_t            rc;
    ngx_uint_t           tag, i;
    ngx_connection_t    *c;
    ngx_mail_session_t  *s;

    c = rev->data;
    s = c->data;

    ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "imap auth state");

    if (rev->timedout) {
        ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
        c->timedout = 1;
        ngx_mail_close_connection(c);
        return;
    }

    if (s->out.len) {
        ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "imap send handler busy");
        s->blocked = 1;
        return;
    }

    s->blocked = 0;

    rc = ngx_mail_read_command(s, c);

    if (rc == NGX_AGAIN || rc == NGX_ERROR) {
        return;
    }

    tag = 1;
    s->text.len = 0;
    s->out.len = sizeof(imap_ok) - 1;
    s->out.data = imap_ok;

    if (rc == NGX_OK) {

        ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0, "imap auth command: %i",
                       s->command);

        if (s->backslash) {

            arg = s->args.elts;

            for (i = 0; i < s->args.nelts; i++) {
                dst = arg[i].data;
                end = dst + arg[i].len;

                for (src = dst; src < end; dst++) {
                    *dst = *src;
                    if (*src++ == '\\') {
                        *dst = *src++;
                    }
                }

                arg[i].len = dst - arg[i].data;
            }

            s->backslash = 0;
        }

        switch (s->mail_state) {

        case ngx_imap_start:

            switch (s->command) {

            case NGX_IMAP_LOGIN:
                rc = ngx_mail_imap_login(s, c);
                break;

            case NGX_IMAP_AUTHENTICATE:
                rc = ngx_mail_imap_authenticate(s, c);
                tag = (rc != NGX_OK);
                break;

            case NGX_IMAP_CAPABILITY:
                rc = ngx_mail_imap_capability(s, c);
                break;

            case NGX_IMAP_LOGOUT:
                s->quit = 1;
                s->text.len = sizeof(imap_bye) - 1;
                s->text.data = imap_bye;
                break;

            case NGX_IMAP_NOOP:
                break;

            case NGX_IMAP_STARTTLS:
                rc = ngx_mail_imap_starttls(s, c);
                break;

            default:
                rc = NGX_MAIL_PARSE_INVALID_COMMAND;
                break;
            }

            break;

        case ngx_imap_auth_login_username:
            rc = ngx_mail_auth_login_username(s, c, 0);

            tag = 0;
            s->out.len = sizeof(imap_password) - 1;
            s->out.data = imap_password;
            s->mail_state = ngx_imap_auth_login_password;

            break;

        case ngx_imap_auth_login_password:
            rc = ngx_mail_auth_login_password(s, c);
            break;

        case ngx_imap_auth_plain:
            rc = ngx_mail_auth_plain(s, c, 0);
            break;

        case ngx_imap_auth_cram_md5:
            rc = ngx_mail_auth_cram_md5(s, c);
            break;
        }

    } else if (rc == NGX_IMAP_NEXT) {
        tag = 0;
        s->out.len = sizeof(imap_next) - 1;
        s->out.data = imap_next;
    }

    switch (rc) {

    case NGX_DONE:
        ngx_mail_auth(s, c);
        return;

    case NGX_ERROR:
        ngx_mail_session_internal_server_error(s);
        return;

    case NGX_MAIL_PARSE_INVALID_COMMAND:
        s->state = 0;
        s->out.len = sizeof(imap_invalid_command) - 1;
        s->out.data = imap_invalid_command;
        s->mail_state = ngx_imap_start;
        break;
    }

    if (tag) {
        if (s->tag.len == 0) {
            s->tag.len = sizeof(imap_star) - 1;
            s->tag.data = (u_char *) imap_star;
        }

        if (s->tagged_line.len < s->tag.len + s->text.len + s->out.len) {
            s->tagged_line.len = s->tag.len + s->text.len + s->out.len;
            s->tagged_line.data = ngx_pnalloc(c->pool, s->tagged_line.len);
            if (s->tagged_line.data == NULL) {
                ngx_mail_close_connection(c);
                return;
            }
        }

        p = s->tagged_line.data;

        if (s->text.len) {
            p = ngx_cpymem(p, s->text.data, s->text.len);
        }

        p = ngx_cpymem(p, s->tag.data, s->tag.len);
        ngx_memcpy(p, s->out.data, s->out.len);

        s->out.len = s->text.len + s->tag.len + s->out.len;
        s->out.data = s->tagged_line.data;
    }

    if (rc != NGX_IMAP_NEXT) {
        s->args.nelts = 0;

        if (s->state) {
            /* preserve tag */
            s->arg_start = s->buffer->start + s->tag.len;
            s->buffer->pos = s->arg_start;
            s->buffer->last = s->arg_start;

        } else {
            s->buffer->pos = s->buffer->start;
            s->buffer->last = s->buffer->start;
            s->tag.len = 0;
        }
    }

    ngx_mail_send(c->write);
}
コード例 #6
0
void
ngx_mail_pop3_auth_state(ngx_event_t *rev)
{
    ngx_int_t            rc;
    ngx_connection_t    *c;
    ngx_mail_session_t  *s;

    c = rev->data;
    s = c->data;

    ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "pop3 auth state");

    if (rev->timedout) {
        ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
        c->timedout = 1;
        ngx_mail_close_connection(c);
        return;
    }

    if (s->out.len) {
        ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "pop3 send handler busy");
        s->blocked = 1;
        return;
    }

    s->blocked = 0;

    rc = ngx_mail_read_command(s, c);

    if (rc == NGX_AGAIN || rc == NGX_ERROR) {
        return;
    }

    ngx_str_set(&s->out, pop3_ok);

    if (rc == NGX_OK) {
        switch (s->mail_state) {

        case ngx_pop3_start:

            switch (s->command) {

            case NGX_POP3_USER:
                rc = ngx_mail_pop3_user(s, c);
                break;

            case NGX_POP3_CAPA:
                rc = ngx_mail_pop3_capa(s, c, 1);
                break;

            case NGX_POP3_APOP:
                rc = ngx_mail_pop3_apop(s, c);
                break;

            case NGX_POP3_AUTH:
                rc = ngx_mail_pop3_auth(s, c);
                break;

            case NGX_POP3_QUIT:
                s->quit = 1;
                break;

            case NGX_POP3_NOOP:
                break;

            case NGX_POP3_STLS:
                rc = ngx_mail_pop3_stls(s, c);
                break;

            default:
                rc = NGX_MAIL_PARSE_INVALID_COMMAND;
                break;
            }

            break;

        case ngx_pop3_user:

            switch (s->command) {

            case NGX_POP3_PASS:
                rc = ngx_mail_pop3_pass(s, c);
                break;

            case NGX_POP3_CAPA:
                rc = ngx_mail_pop3_capa(s, c, 0);
                break;

            case NGX_POP3_QUIT:
                s->quit = 1;
                break;

            case NGX_POP3_NOOP:
                break;

            default:
                rc = NGX_MAIL_PARSE_INVALID_COMMAND;
                break;
            }

            break;

        /* suppress warinings */
        case ngx_pop3_passwd:
            break;

        case ngx_pop3_auth_login_username:
            rc = ngx_mail_auth_login_username(s, c, 0);

            ngx_str_set(&s->out, pop3_password);
            s->mail_state = ngx_pop3_auth_login_password;
            break;

        case ngx_pop3_auth_login_password:
            rc = ngx_mail_auth_login_password(s, c);
            break;

        case ngx_pop3_auth_plain:
            rc = ngx_mail_auth_plain(s, c, 0);
            break;

        case ngx_pop3_auth_cram_md5:
            rc = ngx_mail_auth_cram_md5(s, c);
            break;
        }
    }

    switch (rc) {

    case NGX_DONE:
        ngx_mail_auth(s, c);
        return;

    case NGX_ERROR:
        ngx_mail_session_internal_server_error(s);
        return;

    case NGX_MAIL_PARSE_INVALID_COMMAND:
        s->mail_state = ngx_pop3_start;
        s->state = 0;

        ngx_str_set(&s->out, pop3_invalid_command);

        /* fall through */

    case NGX_OK:

        s->args.nelts = 0;
        s->buffer->pos = s->buffer->start;
        s->buffer->last = s->buffer->start;

        if (s->state) {
            s->arg_start = s->buffer->start;
        }

        ngx_mail_send(c->write);
    }
}