int client_auth_begin(struct client *client, const char *mech_name, const char *init_resp) { if (!client->secured && strcmp(client->ssl_set->ssl, "required") == 0) { if (client->set->auth_verbose) { client_log(client, "Login failed: " "SSL required for authentication"); } client->auth_attempts++; client_auth_result(client, CLIENT_AUTH_RESULT_SSL_REQUIRED, NULL, "Authentication not allowed until SSL/TLS is enabled."); return 1; } client_ref(client); client->auth_initializing = TRUE; sasl_server_auth_begin(client, login_binary->protocol, mech_name, init_resp, sasl_callback); client->auth_initializing = FALSE; if (!client->authenticating) return 1; /* don't handle input until we get the initial auth reply */ if (client->io != NULL) io_remove(&client->io); client_set_auth_waiting(client); return 0; }
bool client_check_plaintext_auth(struct client *client, bool pass_sent) { if (client->secured || !client->set->disable_plaintext_auth) return TRUE; if (client->set->auth_verbose) { client_log(client, "Login failed: " "Plaintext authentication disabled"); } if (pass_sent) { client_notify_status(client, TRUE, "Plaintext authentication not allowed " "without SSL/TLS, but your client did it anyway. " "If anyone was listening, the password was exposed."); } client_auth_result(client, CLIENT_AUTH_RESULT_SSL_REQUIRED, NULL, AUTH_PLAINTEXT_DISABLED_MSG); client->auth_tried_disabled_plaintext = TRUE; client->auth_attempts++; return FALSE; }
static void sasl_callback(struct client *client, enum sasl_server_reply sasl_reply, const char *data, const char *const *args) { struct client_auth_reply reply; i_assert(!client->destroyed || sasl_reply == SASL_SERVER_REPLY_AUTH_ABORTED || sasl_reply == SASL_SERVER_REPLY_MASTER_FAILED); switch (sasl_reply) { case SASL_SERVER_REPLY_SUCCESS: if (client->to_auth_waiting != NULL) timeout_remove(&client->to_auth_waiting); if (args != NULL) { client_auth_parse_args(client, args, &reply); if (client_auth_handle_reply(client, &reply, TRUE)) break; } client_auth_result(client, CLIENT_AUTH_RESULT_SUCCESS, NULL, NULL); client_destroy_success(client, "Login"); break; case SASL_SERVER_REPLY_AUTH_FAILED: case SASL_SERVER_REPLY_AUTH_ABORTED: if (client->to_auth_waiting != NULL) timeout_remove(&client->to_auth_waiting); if (args != NULL) { client_auth_parse_args(client, args, &reply); reply.nologin = TRUE; if (client_auth_handle_reply(client, &reply, FALSE)) break; } if (sasl_reply == SASL_SERVER_REPLY_AUTH_ABORTED) { client_auth_result(client, CLIENT_AUTH_RESULT_ABORTED, NULL, "Authentication aborted by client."); } else if (data == NULL) { client_auth_result(client, CLIENT_AUTH_RESULT_AUTHFAILED, NULL, AUTH_FAILED_MSG); } else { client_auth_result(client, CLIENT_AUTH_RESULT_AUTHFAILED_REASON, NULL, data); } if (!client->destroyed) client_auth_failed(client); break; case SASL_SERVER_REPLY_MASTER_FAILED: if (data != NULL) { /* authentication itself succeeded, we just hit some internal failure. */ client_auth_result(client, CLIENT_AUTH_RESULT_TEMPFAIL, NULL, data); } /* the fd may still be hanging somewhere in kernel or another process. make sure the client gets disconnected. */ if (shutdown(client->fd, SHUT_RDWR) < 0 && errno != ENOTCONN) i_error("shutdown() failed: %m"); if (data == NULL) client_destroy_internal_failure(client); else client_destroy_success(client, data); break; case SASL_SERVER_REPLY_CONTINUE: i_assert(client->v.auth_send_challenge != NULL); client->v.auth_send_challenge(client, data); if (client->to_auth_waiting != NULL) timeout_remove(&client->to_auth_waiting); if (client->auth_response != NULL) str_truncate(client->auth_response, 0); i_assert(client->io == NULL); client->auth_waiting = TRUE; client->io = io_add(client->fd, IO_READ, client_auth_input, client); client_auth_input(client); return; } client_unref(&client); }
static bool client_auth_handle_reply(struct client *client, const struct client_auth_reply *reply, bool success) { if (reply->proxy) { /* we want to proxy the connection to another server. don't do this unless authentication succeeded. with master user proxying we can get FAIL with proxy still set. proxy host=.. [port=..] [destuser=..] pass=.. */ if (!success) return FALSE; if (proxy_start(client, reply) < 0) client_auth_failed(client); return TRUE; } if (reply->host != NULL) { const char *reason; if (reply->reason != NULL) reason = reply->reason; else if (reply->nologin) reason = "Try this server instead."; else reason = "Logged in, but you should use this server instead."; if (reply->nologin) { client_auth_result(client, CLIENT_AUTH_RESULT_REFERRAL_NOLOGIN, reply, reason); } else { client_auth_result(client, CLIENT_AUTH_RESULT_REFERRAL_SUCCESS, reply, reason); return TRUE; } } else if (reply->nologin) { /* Authentication went ok, but for some reason user isn't allowed to log in. Shouldn't probably happen. */ if (reply->reason != NULL) { client_auth_result(client, CLIENT_AUTH_RESULT_AUTHFAILED_REASON, reply, reply->reason); } else if (reply->temp) { const char *timestamp, *msg; timestamp = t_strflocaltime("%Y-%m-%d %H:%M:%S", ioloop_time); msg = t_strdup_printf(AUTH_TEMP_FAILED_MSG" [%s:%s]", my_hostname, timestamp); client_auth_result(client, CLIENT_AUTH_RESULT_TEMPFAIL, reply, msg); } else if (reply->authz_failure) { client_auth_result(client, CLIENT_AUTH_RESULT_AUTHZFAILED, reply, "Authorization failed"); } else { client_auth_result(client, CLIENT_AUTH_RESULT_AUTHFAILED, reply, AUTH_FAILED_MSG); } } else { /* normal login/failure */ return FALSE; } i_assert(reply->nologin); if (!client->destroyed) client_auth_failed(client); return TRUE; }