client-common-auth.c revision de754cb78f75e8b3b994cddafe41c9ed1467c33d
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2002-2013 Dovecot authors, see the included COPYING file */
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen#include "hostpid.h"
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen#include "login-common.h"
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen#include "istream.h"
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen#include "ostream.h"
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen#include "str.h"
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen#include "safe-memset.h"
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen#include "time-util.h"
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen#include "login-proxy.h"
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen#include "auth-client.h"
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen#include "dsasl-client.h"
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen#include "master-service-ssl-settings.h"
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen#include "client-common.h"
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen#include <stdlib.h>
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen#define PROXY_FAILURE_MSG "Account is temporarily unavailable."
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen#define PROXY_DEFAULT_TIMEOUT_MSECS (1000*30)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen/* If we've been waiting auth server to respond for over this many milliseconds,
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen send a "waiting" message. */
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen#define AUTH_WAITING_TIMEOUT_MSECS (30*1000)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen#define AUTH_WAITING_WARNING_TIMEOUT_MSECS (10*1000)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainenstatic void client_auth_failed(struct client *client)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen{
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen i_free_and_null(client->master_data_prefix);
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen if (client->auth_response != NULL)
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen str_truncate(client->auth_response, 0);
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen if (client->auth_initializing || client->destroyed)
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen return;
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen if (client->io != NULL)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen io_remove(&client->io);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen client->io = io_add(client->fd, IO_READ, client_input, client);
56d1345c43bbd28c36b7faa85e4163bd9e874290Timo Sirainen client_input(client);
713a54f695b8ad63826d22ebbe52f55c347e8c88Timo Sirainen}
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainenstatic void client_auth_waiting_timeout(struct client *client)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen{
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen if (!client->notified_auth_ready) {
6766440ffdd8d3ff99a1f732eef212813089bb81Timo Sirainen client_log_warn(client, "Auth process not responding, "
713a54f695b8ad63826d22ebbe52f55c347e8c88Timo Sirainen "delayed sending initial response (greeting)");
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen }
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen client_notify_status(client, FALSE, client->master_tag == 0 ?
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen AUTH_SERVER_WAITING_MSG : AUTH_MASTER_WAITING_MSG);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen timeout_remove(&client->to_auth_waiting);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen}
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainenvoid client_set_auth_waiting(struct client *client)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen{
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen i_assert(client->to_auth_waiting == NULL);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen client->to_auth_waiting =
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen timeout_add(!client->notified_auth_ready ?
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen AUTH_WAITING_WARNING_TIMEOUT_MSECS :
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen AUTH_WAITING_TIMEOUT_MSECS,
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen client_auth_waiting_timeout, client);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen}
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainenstatic void client_auth_parse_args(struct client *client,
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen const char *const *args,
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen struct client_auth_reply *reply_r)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen{
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen const char *key, *value, *p;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen memset(reply_r, 0, sizeof(*reply_r));
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen for (; *args != NULL; args++) {
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen p = strchr(*args, '=');
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen if (p == NULL) {
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen key = *args;
3d8059535db10bacdb96025533d43e826f6762ebTimo Sirainen value = "";
3d8059535db10bacdb96025533d43e826f6762ebTimo Sirainen } else {
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen key = t_strdup_until(*args, p);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen value = p + 1;
f79ba7136a322a10309e5dad9a22d568fe89fb59Timo Sirainen }
f79ba7136a322a10309e5dad9a22d568fe89fb59Timo Sirainen if (strcmp(key, "nologin") == 0)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen reply_r->nologin = TRUE;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen else if (strcmp(key, "proxy") == 0)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen reply_r->proxy = TRUE;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen else if (strcmp(key, "temp") == 0)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen reply_r->temp = TRUE;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen else if (strcmp(key, "authz") == 0)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen reply_r->authz_failure = TRUE;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen else if (strcmp(key, "user_disabled") == 0)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen client->auth_user_disabled = TRUE;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen else if (strcmp(key, "pass_expired") == 0)
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen client->auth_pass_expired = TRUE;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen else if (strcmp(key, "reason") == 0)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen reply_r->reason = value;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen else if (strcmp(key, "host") == 0)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen reply_r->host = value;
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen else if (strcmp(key, "hostip") == 0)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen reply_r->hostip = value;
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen else if (strcmp(key, "port") == 0)
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen reply_r->port = atoi(value);
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen else if (strcmp(key, "destuser") == 0)
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen reply_r->destuser = value;
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen else if (strcmp(key, "pass") == 0)
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen reply_r->password = value;
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen else if (strcmp(key, "proxy_timeout") == 0)
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen reply_r->proxy_timeout_msecs = 1000*atoi(value);
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen else if (strcmp(key, "proxy_refresh") == 0)
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen reply_r->proxy_refresh_secs = atoi(value);
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen else if (strcmp(key, "proxy_mech") == 0)
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen reply_r->proxy_mech = value;
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen else if (strcmp(key, "master") == 0)
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen reply_r->master_user = value;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen else if (strcmp(key, "ssl") == 0) {
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen reply_r->ssl_flags |= PROXY_SSL_FLAG_YES;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen if (strcmp(value, "any-cert") == 0)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen reply_r->ssl_flags |= PROXY_SSL_FLAG_ANY_CERT;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen if (reply_r->port == 0)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen reply_r->port = login_binary->default_ssl_port;
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen } else if (strcmp(key, "starttls") == 0) {
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen reply_r->ssl_flags |= PROXY_SSL_FLAG_YES |
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen PROXY_SSL_FLAG_STARTTLS;
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen if (strcmp(value, "any-cert") == 0)
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen reply_r->ssl_flags |= PROXY_SSL_FLAG_ANY_CERT;
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen } else if (strcmp(key, "user") == 0) {
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen /* already handled in login-common */
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen } else if (client->set->auth_debug)
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen i_debug("Ignoring unknown passdb extra field: %s", key);
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen }
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen if (reply_r->port == 0)
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen reply_r->port = login_binary->default_port;
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen if (reply_r->destuser == NULL)
4d981bcd01bd1dd5248095b0e59957949332657eTimo Sirainen reply_r->destuser = client->virtual_user;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen}
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainenstatic void proxy_free_password(struct client *client)
f79ba7136a322a10309e5dad9a22d568fe89fb59Timo Sirainen{
f79ba7136a322a10309e5dad9a22d568fe89fb59Timo Sirainen if (client->proxy_password == NULL)
f79ba7136a322a10309e5dad9a22d568fe89fb59Timo Sirainen return;
f79ba7136a322a10309e5dad9a22d568fe89fb59Timo Sirainen
f79ba7136a322a10309e5dad9a22d568fe89fb59Timo Sirainen safe_memset(client->proxy_password, 0, strlen(client->proxy_password));
f79ba7136a322a10309e5dad9a22d568fe89fb59Timo Sirainen i_free_and_null(client->proxy_password);
f79ba7136a322a10309e5dad9a22d568fe89fb59Timo Sirainen}
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainenvoid client_proxy_finish_destroy_client(struct client *client)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen{
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen string_t *str = t_str_new(128);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen if (client->input->closed) {
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen /* input stream got closed in client_send_raw_data().
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen In most places we don't have to check for this explicitly,
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen but login_proxy_detach() attempts to get and use the
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen istream's fd, which is now -1. */
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen client_destroy(client, "Disconnected");
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen return;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen }
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen str_printfa(str, "proxy(%s): started proxying to %s:%u",
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen client->virtual_user,
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen login_proxy_get_host(client->login_proxy),
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen login_proxy_get_port(client->login_proxy));
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen if (strcmp(client->virtual_user, client->proxy_user) != 0) {
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen /* remote username is different, log it */
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen str_append_c(str, '/');
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen str_append(str, client->proxy_user);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen }
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen if (client->proxy_master_user != NULL)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen str_printfa(str, " (master %s)", client->proxy_master_user);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
3d8059535db10bacdb96025533d43e826f6762ebTimo Sirainen login_proxy_detach(client->login_proxy);
3d8059535db10bacdb96025533d43e826f6762ebTimo Sirainen client_destroy_success(client, str_c(str));
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen}
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainenstatic void client_proxy_error(struct client *client, const char *text)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen{
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen client->v.proxy_error(client, text);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen}
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainenvoid client_proxy_log_failure(struct client *client, const char *line)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen{
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen string_t *str = t_str_new(128);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen str_printfa(str, "proxy(%s): Login failed to %s:%u",
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen client->virtual_user,
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen login_proxy_get_host(client->login_proxy),
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen login_proxy_get_port(client->login_proxy));
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen if (strcmp(client->virtual_user, client->proxy_user) != 0) {
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen /* remote username is different, log it */
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen str_append_c(str, '/');
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen str_append(str, client->proxy_user);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen }
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen if (client->proxy_master_user != NULL)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen str_printfa(str, " (master %s)", client->proxy_master_user);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen str_append(str, ": ");
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen str_append(str, line);
3d8059535db10bacdb96025533d43e826f6762ebTimo Sirainen i_info("%s", str_c(str));
3d8059535db10bacdb96025533d43e826f6762ebTimo Sirainen}
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainenvoid client_proxy_failed(struct client *client, bool send_line)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen{
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen if (send_line) {
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen client_proxy_error(client, PROXY_FAILURE_MSG);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen }
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen if (client->proxy_sasl_client != NULL)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen dsasl_client_free(&client->proxy_sasl_client);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen login_proxy_free(&client->login_proxy);
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainen proxy_free_password(client);
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainen i_free_and_null(client->proxy_user);
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainen i_free_and_null(client->proxy_master_user);
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainen
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainen /* call this last - it may destroy the client */
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainen client_auth_failed(client);
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainen}
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainen
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainenstatic const char *get_disconnect_reason(struct istream *input)
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainen{
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainen errno = input->stream_errno;
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainen return errno == 0 || errno == EPIPE ? "Connection closed" :
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainen t_strdup_printf("Connection closed: %m");
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainen}
3d8059535db10bacdb96025533d43e826f6762ebTimo Sirainen
3d8059535db10bacdb96025533d43e826f6762ebTimo Sirainenstatic void proxy_input(struct client *client)
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainen{
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainen struct istream *input;
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainen const char *line;
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainen unsigned int duration;
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainen
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainen if (client->login_proxy == NULL) {
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainen /* we're just freeing the proxy */
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainen return;
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainen }
a601cdf61506674a681195acfe57c9864bd3f7acTimo Sirainen
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen input = login_proxy_get_istream(client->login_proxy);
01c4df2aded7cb44bbaf69d61bd6d9e496b919a4Timo Sirainen if (input == NULL) {
01c4df2aded7cb44bbaf69d61bd6d9e496b919a4Timo Sirainen if (client->destroyed) {
01c4df2aded7cb44bbaf69d61bd6d9e496b919a4Timo Sirainen /* we came here from client_destroy() */
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen return;
f86f7ec83f6626701137ad86fc7c7d431367ea83Timo Sirainen }
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen /* failed for some reason, probably server disconnected */
ab1e085cf10b68a7e6a8889156493a3369a194e9Timo Sirainen client_proxy_failed(client, TRUE);
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen return;
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen }
f942b7b96a5c3c6756a6ea7bc3de0cd01bcb07fbTimo Sirainen
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen i_assert(!client->destroyed);
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen
f86f7ec83f6626701137ad86fc7c7d431367ea83Timo Sirainen switch (i_stream_read(input)) {
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen case -2:
f86f7ec83f6626701137ad86fc7c7d431367ea83Timo Sirainen client_log_err(client, "proxy: Remote input buffer full");
f86f7ec83f6626701137ad86fc7c7d431367ea83Timo Sirainen client_proxy_failed(client, TRUE);
f942b7b96a5c3c6756a6ea7bc3de0cd01bcb07fbTimo Sirainen return;
f942b7b96a5c3c6756a6ea7bc3de0cd01bcb07fbTimo Sirainen case -1:
f942b7b96a5c3c6756a6ea7bc3de0cd01bcb07fbTimo Sirainen line = i_stream_next_line(input);
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen duration = ioloop_time - client->created;
3d8059535db10bacdb96025533d43e826f6762ebTimo Sirainen client_log_err(client, t_strdup_printf(
3d8059535db10bacdb96025533d43e826f6762ebTimo Sirainen "proxy: Remote %s:%u disconnected: %s "
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen "(state=%u, duration=%us)%s",
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen login_proxy_get_host(client->login_proxy),
f942b7b96a5c3c6756a6ea7bc3de0cd01bcb07fbTimo Sirainen login_proxy_get_port(client->login_proxy),
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen get_disconnect_reason(input),
f86f7ec83f6626701137ad86fc7c7d431367ea83Timo Sirainen client->proxy_state, duration,
f86f7ec83f6626701137ad86fc7c7d431367ea83Timo Sirainen line == NULL ? "" : t_strdup_printf(
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen " - BUG: line not read: %s", line)));
f942b7b96a5c3c6756a6ea7bc3de0cd01bcb07fbTimo Sirainen client_proxy_failed(client, TRUE);
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen return;
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen }
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen while ((line = i_stream_next_line(input)) != NULL) {
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen if (client->v.proxy_parse_line(client, line) != 0)
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen break;
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen }
01c4df2aded7cb44bbaf69d61bd6d9e496b919a4Timo Sirainen}
01c4df2aded7cb44bbaf69d61bd6d9e496b919a4Timo Sirainen
01c4df2aded7cb44bbaf69d61bd6d9e496b919a4Timo Sirainenstatic int proxy_start(struct client *client,
01c4df2aded7cb44bbaf69d61bd6d9e496b919a4Timo Sirainen const struct client_auth_reply *reply)
01c4df2aded7cb44bbaf69d61bd6d9e496b919a4Timo Sirainen{
01c4df2aded7cb44bbaf69d61bd6d9e496b919a4Timo Sirainen struct login_proxy_settings proxy_set;
01c4df2aded7cb44bbaf69d61bd6d9e496b919a4Timo Sirainen const struct dsasl_client_mech *sasl_mech = NULL;
01c4df2aded7cb44bbaf69d61bd6d9e496b919a4Timo Sirainen
01c4df2aded7cb44bbaf69d61bd6d9e496b919a4Timo Sirainen i_assert(reply->destuser != NULL);
01c4df2aded7cb44bbaf69d61bd6d9e496b919a4Timo Sirainen i_assert(!client->destroyed);
01c4df2aded7cb44bbaf69d61bd6d9e496b919a4Timo Sirainen i_assert(client->proxy_sasl_client == NULL);
01c4df2aded7cb44bbaf69d61bd6d9e496b919a4Timo Sirainen
01c4df2aded7cb44bbaf69d61bd6d9e496b919a4Timo Sirainen client->proxy_mech = NULL;
01c4df2aded7cb44bbaf69d61bd6d9e496b919a4Timo Sirainen client->v.proxy_reset(client);
01c4df2aded7cb44bbaf69d61bd6d9e496b919a4Timo Sirainen
01c4df2aded7cb44bbaf69d61bd6d9e496b919a4Timo Sirainen if (reply->password == NULL) {
01c4df2aded7cb44bbaf69d61bd6d9e496b919a4Timo Sirainen client_log_err(client, "proxy: password not given");
01c4df2aded7cb44bbaf69d61bd6d9e496b919a4Timo Sirainen client_proxy_error(client, PROXY_FAILURE_MSG);
01c4df2aded7cb44bbaf69d61bd6d9e496b919a4Timo Sirainen return -1;
01c4df2aded7cb44bbaf69d61bd6d9e496b919a4Timo Sirainen }
01c4df2aded7cb44bbaf69d61bd6d9e496b919a4Timo Sirainen if (reply->host == NULL || *reply->host == '\0') {
01c4df2aded7cb44bbaf69d61bd6d9e496b919a4Timo Sirainen client_log_err(client, "proxy: host not given");
01c4df2aded7cb44bbaf69d61bd6d9e496b919a4Timo Sirainen client_proxy_error(client, PROXY_FAILURE_MSG);
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen return -1;
01c4df2aded7cb44bbaf69d61bd6d9e496b919a4Timo Sirainen }
01c4df2aded7cb44bbaf69d61bd6d9e496b919a4Timo Sirainen
01c4df2aded7cb44bbaf69d61bd6d9e496b919a4Timo Sirainen if (reply->proxy_mech != NULL) {
01c4df2aded7cb44bbaf69d61bd6d9e496b919a4Timo Sirainen sasl_mech = dsasl_client_mech_find(reply->proxy_mech);
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen if (sasl_mech == NULL) {
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen client_log_err(client, t_strdup_printf(
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen "proxy: Unsupported SASL mechanism %s",
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen reply->proxy_mech));
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen client_proxy_error(client, PROXY_FAILURE_MSG);
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen return -1;
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen }
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen } else if (reply->master_user != NULL) {
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen /* have to use PLAIN authentication with master user logins */
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen sasl_mech = &dsasl_client_mech_plain;
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen }
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen i_assert(client->refcount > 1);
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen if (client->destroyed) {
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen /* connection_queue_add() decided that we were the oldest
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen connection and killed us. */
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen return -1;
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen }
f9ca41ec7a26e8e571e268ee5c8da2e5745a4ab0Timo Sirainen if (login_proxy_is_ourself(client, reply->host, reply->port,
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen reply->destuser)) {
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen client_log_err(client, "Proxying loops to itself");
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen client_proxy_error(client, PROXY_FAILURE_MSG);
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen return -1;
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen }
f942b7b96a5c3c6756a6ea7bc3de0cd01bcb07fbTimo Sirainen
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen memset(&proxy_set, 0, sizeof(proxy_set));
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen proxy_set.host = reply->host;
01c4df2aded7cb44bbaf69d61bd6d9e496b919a4Timo Sirainen if (reply->hostip != NULL &&
01c4df2aded7cb44bbaf69d61bd6d9e496b919a4Timo Sirainen net_addr2ip(reply->hostip, &proxy_set.ip) < 0)
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen proxy_set.ip.family = 0;
f86f7ec83f6626701137ad86fc7c7d431367ea83Timo Sirainen proxy_set.port = reply->port;
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen proxy_set.connect_timeout_msecs = reply->proxy_timeout_msecs;
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen if (proxy_set.connect_timeout_msecs == 0)
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen proxy_set.connect_timeout_msecs = PROXY_DEFAULT_TIMEOUT_MSECS;
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen proxy_set.notify_refresh_secs = reply->proxy_refresh_secs;
f9ca41ec7a26e8e571e268ee5c8da2e5745a4ab0Timo Sirainen proxy_set.ssl_flags = reply->ssl_flags;
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen
f9ca41ec7a26e8e571e268ee5c8da2e5745a4ab0Timo Sirainen if (login_proxy_new(client, &proxy_set, proxy_input) < 0) {
f9ca41ec7a26e8e571e268ee5c8da2e5745a4ab0Timo Sirainen client_proxy_error(client, PROXY_FAILURE_MSG);
f9ca41ec7a26e8e571e268ee5c8da2e5745a4ab0Timo Sirainen return -1;
f9ca41ec7a26e8e571e268ee5c8da2e5745a4ab0Timo Sirainen }
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen client->proxy_mech = sasl_mech;
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen client->proxy_user = i_strdup(reply->destuser);
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen client->proxy_master_user = i_strdup(reply->master_user);
f9ca41ec7a26e8e571e268ee5c8da2e5745a4ab0Timo Sirainen client->proxy_password = i_strdup(reply->password);
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen /* disable input until authentication is finished */
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen if (client->io != NULL)
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen io_remove(&client->io);
f9ca41ec7a26e8e571e268ee5c8da2e5745a4ab0Timo Sirainen return 0;
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen}
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainenstatic void ATTR_NULL(3, 4)
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainenclient_auth_result(struct client *client, enum client_auth_result result,
d4b03b1b224603afbc2468f07ffb80cc872b1f9fTimo Sirainen const struct client_auth_reply *reply, const char *text)
d4b03b1b224603afbc2468f07ffb80cc872b1f9fTimo Sirainen{
d4b03b1b224603afbc2468f07ffb80cc872b1f9fTimo Sirainen client->v.auth_result(client, result, reply, text);
d4b03b1b224603afbc2468f07ffb80cc872b1f9fTimo Sirainen}
d4b03b1b224603afbc2468f07ffb80cc872b1f9fTimo Sirainen
f9ca41ec7a26e8e571e268ee5c8da2e5745a4ab0Timo Sirainenstatic bool
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainenclient_auth_handle_reply(struct client *client,
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen const struct client_auth_reply *reply, bool success)
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen{
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen if (reply->proxy) {
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen /* we want to proxy the connection to another server.
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen don't do this unless authentication succeeded. with
f9ca41ec7a26e8e571e268ee5c8da2e5745a4ab0Timo Sirainen master user proxying we can get FAIL with proxy still set.
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen proxy host=.. [port=..] [destuser=..] pass=.. */
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen if (!success)
01c4df2aded7cb44bbaf69d61bd6d9e496b919a4Timo Sirainen return FALSE;
01c4df2aded7cb44bbaf69d61bd6d9e496b919a4Timo Sirainen if (proxy_start(client, reply) < 0)
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen client_auth_failed(client);
01c4df2aded7cb44bbaf69d61bd6d9e496b919a4Timo Sirainen return TRUE;
01c4df2aded7cb44bbaf69d61bd6d9e496b919a4Timo Sirainen }
f942b7b96a5c3c6756a6ea7bc3de0cd01bcb07fbTimo Sirainen
01c4df2aded7cb44bbaf69d61bd6d9e496b919a4Timo Sirainen if (reply->host != NULL) {
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen const char *reason;
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen if (reply->reason != NULL)
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen reason = reply->reason;
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen else if (reply->nologin)
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen reason = "Try this server instead.";
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen else
95c13a27352739261c53ecd23fe2f0c3d61aa06fTimo Sirainen reason = "Logged in, but you should use this server instead.";
95c13a27352739261c53ecd23fe2f0c3d61aa06fTimo Sirainen
f9ca41ec7a26e8e571e268ee5c8da2e5745a4ab0Timo Sirainen if (reply->nologin) {
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen client_auth_result(client,
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen CLIENT_AUTH_RESULT_REFERRAL_NOLOGIN,
95c13a27352739261c53ecd23fe2f0c3d61aa06fTimo Sirainen reply, reason);
f9ca41ec7a26e8e571e268ee5c8da2e5745a4ab0Timo Sirainen } else {
f9ca41ec7a26e8e571e268ee5c8da2e5745a4ab0Timo Sirainen client_auth_result(client,
f9ca41ec7a26e8e571e268ee5c8da2e5745a4ab0Timo Sirainen CLIENT_AUTH_RESULT_REFERRAL_SUCCESS,
95c13a27352739261c53ecd23fe2f0c3d61aa06fTimo Sirainen reply, reason);
95c13a27352739261c53ecd23fe2f0c3d61aa06fTimo Sirainen return TRUE;
95c13a27352739261c53ecd23fe2f0c3d61aa06fTimo Sirainen }
95c13a27352739261c53ecd23fe2f0c3d61aa06fTimo Sirainen } else if (reply->nologin) {
95c13a27352739261c53ecd23fe2f0c3d61aa06fTimo Sirainen /* Authentication went ok, but for some reason user isn't
95c13a27352739261c53ecd23fe2f0c3d61aa06fTimo Sirainen allowed to log in. Shouldn't probably happen. */
95c13a27352739261c53ecd23fe2f0c3d61aa06fTimo Sirainen if (reply->reason != NULL) {
95c13a27352739261c53ecd23fe2f0c3d61aa06fTimo Sirainen client_auth_result(client,
95c13a27352739261c53ecd23fe2f0c3d61aa06fTimo Sirainen CLIENT_AUTH_RESULT_AUTHFAILED_REASON,
95c13a27352739261c53ecd23fe2f0c3d61aa06fTimo Sirainen reply, reply->reason);
95c13a27352739261c53ecd23fe2f0c3d61aa06fTimo Sirainen } else if (reply->temp) {
95c13a27352739261c53ecd23fe2f0c3d61aa06fTimo Sirainen const char *timestamp, *msg;
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen timestamp = t_strflocaltime("%Y-%m-%d %H:%M:%S", ioloop_time);
ca096c557fac1cf87dd5f129c202b2c1d990ff59Timo Sirainen msg = t_strdup_printf(AUTH_TEMP_FAILED_MSG" [%s:%s]",
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen my_hostname, timestamp);
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen client_auth_result(client, CLIENT_AUTH_RESULT_TEMPFAIL,
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen reply, msg);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen } else if (reply->authz_failure) {
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen client_auth_result(client,
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen CLIENT_AUTH_RESULT_AUTHZFAILED, reply,
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen "Authorization failed");
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen } else {
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen client_auth_result(client,
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen CLIENT_AUTH_RESULT_AUTHFAILED, reply,
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen AUTH_FAILED_MSG);
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen }
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen } else {
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen /* normal login/failure */
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen return FALSE;
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen }
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen i_assert(reply->nologin);
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen if (!client->destroyed)
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen client_auth_failed(client);
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen return TRUE;
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen}
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainenvoid client_auth_respond(struct client *client, const char *response)
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen{
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen client->auth_waiting = FALSE;
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen client_set_auth_waiting(client);
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen auth_client_request_continue(client->auth_request, response);
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen io_remove(&client->io);
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen}
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainenvoid client_auth_abort(struct client *client)
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen{
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen sasl_server_auth_abort(client);
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen}
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainenvoid client_auth_fail(struct client *client, const char *text)
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen{
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen sasl_server_auth_failed(client, text);
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen}
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainenint client_auth_read_line(struct client *client)
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen{
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen const unsigned char *data;
c58f46762024d6df2c5ef5590be75c8abbe7e5d7Timo Sirainen size_t i, size;
244d1dd1a501d1e4b53d8af9a2704640b276b7daTimo Sirainen unsigned int len;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen if (i_stream_read_data(client->input, &data, &size, 0) == -1) {
244d1dd1a501d1e4b53d8af9a2704640b276b7daTimo Sirainen client_destroy(client, "Disconnected");
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen return -1;
89f9c7bf3cc041de11974af9ac45f543e9761444Timo Sirainen }
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen /* see if we have a full line */
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen for (i = 0; i < size; i++) {
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen if (data[i] == '\n')
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen break;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen }
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen if (client->auth_response == NULL)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen client->auth_response = str_new(default_pool, I_MAX(i+1, 256));
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen if (str_len(client->auth_response) + i > LOGIN_MAX_AUTH_BUF_SIZE) {
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen client_destroy(client, "Authentication response too large");
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen return -1;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen }
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen str_append_n(client->auth_response, data, i);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen i_stream_skip(client->input, i == size ? size : i+1);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen /* drop trailing \r */
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen len = str_len(client->auth_response);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen if (len > 0 && str_c(client->auth_response)[len-1] == '\r')
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen str_truncate(client->auth_response, len-1);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen return i < size;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen}
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainenvoid client_auth_parse_response(struct client *client)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen{
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen if (client_auth_read_line(client) <= 0)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen return;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen if (strcmp(str_c(client->auth_response), "*") == 0) {
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen sasl_server_auth_abort(client);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen return;
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen }
5592b04741577d014760097fc40f0f5276241754Aki Tuomi
5592b04741577d014760097fc40f0f5276241754Aki Tuomi client_auth_respond(client, str_c(client->auth_response));
5592b04741577d014760097fc40f0f5276241754Aki Tuomi memset(str_c_modifiable(client->auth_response), 0,
5592b04741577d014760097fc40f0f5276241754Aki Tuomi str_len(client->auth_response));
5592b04741577d014760097fc40f0f5276241754Aki Tuomi}
5592b04741577d014760097fc40f0f5276241754Aki Tuomi
5592b04741577d014760097fc40f0f5276241754Aki Tuomistatic void client_auth_input(struct client *client)
5592b04741577d014760097fc40f0f5276241754Aki Tuomi{
5592b04741577d014760097fc40f0f5276241754Aki Tuomi i_assert(client->v.auth_parse_response != NULL);
5592b04741577d014760097fc40f0f5276241754Aki Tuomi client->v.auth_parse_response(client);
5592b04741577d014760097fc40f0f5276241754Aki Tuomi}
5592b04741577d014760097fc40f0f5276241754Aki Tuomi
5592b04741577d014760097fc40f0f5276241754Aki Tuomivoid client_auth_send_challenge(struct client *client, const char *data)
5592b04741577d014760097fc40f0f5276241754Aki Tuomi{
5592b04741577d014760097fc40f0f5276241754Aki Tuomi struct const_iovec iov[3];
5592b04741577d014760097fc40f0f5276241754Aki Tuomi
5592b04741577d014760097fc40f0f5276241754Aki Tuomi iov[0].iov_base = "+ ";
5592b04741577d014760097fc40f0f5276241754Aki Tuomi iov[0].iov_len = 2;
5592b04741577d014760097fc40f0f5276241754Aki Tuomi iov[1].iov_base = data;
5592b04741577d014760097fc40f0f5276241754Aki Tuomi iov[1].iov_len = strlen(data);
5592b04741577d014760097fc40f0f5276241754Aki Tuomi iov[2].iov_base = "\r\n";
5592b04741577d014760097fc40f0f5276241754Aki Tuomi iov[2].iov_len = 2;
5592b04741577d014760097fc40f0f5276241754Aki Tuomi
5592b04741577d014760097fc40f0f5276241754Aki Tuomi o_stream_nsendv(client->output, iov, 3);
5592b04741577d014760097fc40f0f5276241754Aki Tuomi}
5592b04741577d014760097fc40f0f5276241754Aki Tuomi
5592b04741577d014760097fc40f0f5276241754Aki Tuomistatic void
5592b04741577d014760097fc40f0f5276241754Aki Tuomisasl_callback(struct client *client, enum sasl_server_reply sasl_reply,
5592b04741577d014760097fc40f0f5276241754Aki Tuomi const char *data, const char *const *args)
5592b04741577d014760097fc40f0f5276241754Aki Tuomi{
5592b04741577d014760097fc40f0f5276241754Aki Tuomi struct client_auth_reply reply;
5592b04741577d014760097fc40f0f5276241754Aki Tuomi
5592b04741577d014760097fc40f0f5276241754Aki Tuomi i_assert(!client->destroyed ||
5592b04741577d014760097fc40f0f5276241754Aki Tuomi sasl_reply == SASL_SERVER_REPLY_AUTH_ABORTED ||
5592b04741577d014760097fc40f0f5276241754Aki Tuomi sasl_reply == SASL_SERVER_REPLY_MASTER_FAILED);
5592b04741577d014760097fc40f0f5276241754Aki Tuomi
5592b04741577d014760097fc40f0f5276241754Aki Tuomi switch (sasl_reply) {
5592b04741577d014760097fc40f0f5276241754Aki Tuomi case SASL_SERVER_REPLY_SUCCESS:
5592b04741577d014760097fc40f0f5276241754Aki Tuomi if (client->to_auth_waiting != NULL)
5592b04741577d014760097fc40f0f5276241754Aki Tuomi timeout_remove(&client->to_auth_waiting);
5592b04741577d014760097fc40f0f5276241754Aki Tuomi if (args != NULL) {
5592b04741577d014760097fc40f0f5276241754Aki Tuomi client_auth_parse_args(client, args, &reply);
5592b04741577d014760097fc40f0f5276241754Aki Tuomi if (client_auth_handle_reply(client, &reply, TRUE))
5592b04741577d014760097fc40f0f5276241754Aki Tuomi break;
5592b04741577d014760097fc40f0f5276241754Aki Tuomi }
5592b04741577d014760097fc40f0f5276241754Aki Tuomi client_auth_result(client, CLIENT_AUTH_RESULT_SUCCESS,
5592b04741577d014760097fc40f0f5276241754Aki Tuomi NULL, NULL);
5592b04741577d014760097fc40f0f5276241754Aki Tuomi client_destroy_success(client, "Login");
5592b04741577d014760097fc40f0f5276241754Aki Tuomi break;
5592b04741577d014760097fc40f0f5276241754Aki Tuomi case SASL_SERVER_REPLY_AUTH_FAILED:
5592b04741577d014760097fc40f0f5276241754Aki Tuomi case SASL_SERVER_REPLY_AUTH_ABORTED:
5592b04741577d014760097fc40f0f5276241754Aki Tuomi if (client->to_auth_waiting != NULL)
5592b04741577d014760097fc40f0f5276241754Aki Tuomi timeout_remove(&client->to_auth_waiting);
5592b04741577d014760097fc40f0f5276241754Aki Tuomi if (args != NULL) {
5592b04741577d014760097fc40f0f5276241754Aki Tuomi client_auth_parse_args(client, args, &reply);
5592b04741577d014760097fc40f0f5276241754Aki Tuomi reply.nologin = TRUE;
5592b04741577d014760097fc40f0f5276241754Aki Tuomi if (client_auth_handle_reply(client, &reply, FALSE))
5592b04741577d014760097fc40f0f5276241754Aki Tuomi break;
5592b04741577d014760097fc40f0f5276241754Aki Tuomi }
5592b04741577d014760097fc40f0f5276241754Aki Tuomi
5592b04741577d014760097fc40f0f5276241754Aki Tuomi if (sasl_reply == SASL_SERVER_REPLY_AUTH_ABORTED) {
5592b04741577d014760097fc40f0f5276241754Aki Tuomi client_auth_result(client, CLIENT_AUTH_RESULT_ABORTED,
5592b04741577d014760097fc40f0f5276241754Aki Tuomi NULL, "Authentication aborted by client.");
5592b04741577d014760097fc40f0f5276241754Aki Tuomi } else if (data == NULL) {
5592b04741577d014760097fc40f0f5276241754Aki Tuomi client_auth_result(client,
5592b04741577d014760097fc40f0f5276241754Aki Tuomi CLIENT_AUTH_RESULT_AUTHFAILED, NULL,
5592b04741577d014760097fc40f0f5276241754Aki Tuomi AUTH_FAILED_MSG);
5592b04741577d014760097fc40f0f5276241754Aki Tuomi } else {
5592b04741577d014760097fc40f0f5276241754Aki Tuomi client_auth_result(client,
5592b04741577d014760097fc40f0f5276241754Aki Tuomi CLIENT_AUTH_RESULT_AUTHFAILED_REASON, NULL,
5592b04741577d014760097fc40f0f5276241754Aki Tuomi data);
5592b04741577d014760097fc40f0f5276241754Aki Tuomi }
5592b04741577d014760097fc40f0f5276241754Aki Tuomi
5592b04741577d014760097fc40f0f5276241754Aki Tuomi if (!client->destroyed)
5592b04741577d014760097fc40f0f5276241754Aki Tuomi client_auth_failed(client);
5592b04741577d014760097fc40f0f5276241754Aki Tuomi break;
5592b04741577d014760097fc40f0f5276241754Aki Tuomi case SASL_SERVER_REPLY_MASTER_FAILED:
5592b04741577d014760097fc40f0f5276241754Aki Tuomi if (data != NULL) {
5592b04741577d014760097fc40f0f5276241754Aki Tuomi /* authentication itself succeeded, we just hit some
5592b04741577d014760097fc40f0f5276241754Aki Tuomi internal failure. */
5592b04741577d014760097fc40f0f5276241754Aki Tuomi client_auth_result(client, CLIENT_AUTH_RESULT_TEMPFAIL,
5592b04741577d014760097fc40f0f5276241754Aki Tuomi NULL, data);
5592b04741577d014760097fc40f0f5276241754Aki Tuomi }
5592b04741577d014760097fc40f0f5276241754Aki Tuomi
5592b04741577d014760097fc40f0f5276241754Aki Tuomi /* the fd may still be hanging somewhere in kernel or another
5592b04741577d014760097fc40f0f5276241754Aki Tuomi process. make sure the client gets disconnected. */
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen if (shutdown(client->fd, SHUT_RDWR) < 0 && errno != ENOTCONN)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen i_error("shutdown() failed: %m");
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen if (data == NULL)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen client_destroy_internal_failure(client);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen else
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen client_destroy_success(client, data);
5592b04741577d014760097fc40f0f5276241754Aki Tuomi break;
5592b04741577d014760097fc40f0f5276241754Aki Tuomi case SASL_SERVER_REPLY_CONTINUE:
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen i_assert(client->v.auth_send_challenge != NULL);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen client->v.auth_send_challenge(client, data);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen if (client->to_auth_waiting != NULL)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen timeout_remove(&client->to_auth_waiting);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen if (client->auth_response != NULL)
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen str_truncate(client->auth_response, 0);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen
5592b04741577d014760097fc40f0f5276241754Aki Tuomi i_assert(client->io == NULL);
51f750db859e62e2c58a61806b53e0adb13e0775Timo Sirainen client->auth_waiting = TRUE;
client->io = io_add(client->fd, IO_READ,
client_auth_input, client);
client_auth_input(client);
return;
}
client_unref(&client);
}
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 &&
strcmp(client->ssl_set->ssl, "required") != 0))
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;
}
void clients_notify_auth_connected(void)
{
struct client *client, *next;
for (client = clients; client != NULL; client = next) {
next = client->next;
if (client->to_auth_waiting != NULL)
timeout_remove(&client->to_auth_waiting);
client_notify_auth_ready(client);
if (client->input_blocked) {
client->input_blocked = FALSE;
client_input(client);
}
}
}