client-common.c revision 0256180043b9f55b606b523b775e8b23b1b12f83
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* Copyright (c) 2002-2017 Dovecot authors, see the included COPYING file */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "login-common.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "array.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "hostpid.h"
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen#include "llist.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "istream.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "ostream.h"
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen#include "iostream-proxy.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "iostream-rawlog.h"
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen#include "process-title.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "hook-build.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "buffer.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "str.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "strescape.h"
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen#include "base64.h"
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen#include "str-sanitize.h"
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen#include "safe-memset.h"
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen#include "var-expand.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "master-interface.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "master-service.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "master-service-ssl-settings.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "master-auth.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "auth-client.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "dsasl-client.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "login-proxy.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "ssl-proxy.h"
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen#include "client-common.h"
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen
5626ae5e3316eced244adb6485c0927f1c7fdc41Timo Sirainenstruct client *clients = NULL;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainenstatic struct client *last_client = NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic unsigned int clients_count = 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic struct client *client_fd_proxies = NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic unsigned int client_fd_proxies_count = 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstruct login_client_module_hooks {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct module *module;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const struct login_client_hooks *hooks;
ee246b46953e4b94b2f22e093373674fa9155500Timo Sirainen};
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen
ee246b46953e4b94b2f22e093373674fa9155500Timo Sirainenstatic ARRAY(struct login_client_module_hooks) module_hooks = ARRAY_INIT;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainenvoid login_client_hooks_add(struct module *module,
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen const struct login_client_hooks *hooks)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct login_client_module_hooks *hook;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen hook = array_append_space(&module_hooks);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen hook->module = module;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen hook->hooks = hooks;
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen}
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainenvoid login_client_hooks_remove(const struct login_client_hooks *hooks)
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen{
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen const struct login_client_module_hooks *module_hook;
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen unsigned int idx = UINT_MAX;
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen array_foreach(&module_hooks, module_hook) {
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen if (module_hook->hooks == hooks) {
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen idx = array_foreach_idx(&module_hooks, module_hook);
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen break;
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen }
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen }
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen i_assert(idx != UINT_MAX);
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen array_delete(&module_hooks, idx, 1);
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen}
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainenstatic void hook_login_client_allocated(struct client *client)
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen{
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen const struct login_client_module_hooks *module_hook;
5626ae5e3316eced244adb6485c0927f1c7fdc41Timo Sirainen struct hook_build_context *ctx;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen ctx = hook_build_init((void *)&client->v, sizeof(client->v));
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen client->vlast = &client->v;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen array_foreach(&module_hooks, module_hook) {
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen if (module_hook->hooks->client_allocated != NULL) T_BEGIN {
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen module_hook->hooks->client_allocated(client);
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen hook_build_update(ctx, client->vlast);
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen } T_END;
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen }
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen client->vlast = NULL;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen hook_build_deinit(&ctx);
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen}
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainenstatic void client_idle_disconnect_timeout(struct client *client)
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen{
5626ae5e3316eced244adb6485c0927f1c7fdc41Timo Sirainen const char *user_reason, *destroy_reason;
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen unsigned int secs;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen if (client->master_tag != 0) {
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen secs = ioloop_time - client->auth_finished;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen user_reason = "Timeout while finishing login.";
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen destroy_reason = t_strdup_printf(
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen "Timeout while finishing login (waited %u secs)", secs);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen client_log_err(client, destroy_reason);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen } else if (client->auth_request != NULL) {
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen user_reason =
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen "Disconnected for inactivity during authentication.";
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen destroy_reason =
5626ae5e3316eced244adb6485c0927f1c7fdc41Timo Sirainen "Disconnected: Inactivity during authentication";
5626ae5e3316eced244adb6485c0927f1c7fdc41Timo Sirainen } else if (client->login_proxy != NULL) {
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen secs = ioloop_time - client->created;
5626ae5e3316eced244adb6485c0927f1c7fdc41Timo Sirainen user_reason = "Timeout while finishing login.";
5626ae5e3316eced244adb6485c0927f1c7fdc41Timo Sirainen destroy_reason = t_strdup_printf(
5626ae5e3316eced244adb6485c0927f1c7fdc41Timo Sirainen "proxy: Logging in to %s:%u timed out "
5626ae5e3316eced244adb6485c0927f1c7fdc41Timo Sirainen "(state=%s, duration=%us)",
5626ae5e3316eced244adb6485c0927f1c7fdc41Timo Sirainen login_proxy_get_host(client->login_proxy),
5626ae5e3316eced244adb6485c0927f1c7fdc41Timo Sirainen login_proxy_get_port(client->login_proxy),
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen client_proxy_get_state(client), secs);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen client_log_err(client, destroy_reason);
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen } else {
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen user_reason = "Disconnected for inactivity.";
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen destroy_reason = "Disconnected: Inactivity";
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen }
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen client_notify_disconnect(client, CLIENT_DISCONNECT_TIMEOUT, user_reason);
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen client_destroy(client, destroy_reason);
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen}
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainenstatic void client_open_streams(struct client *client)
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen{
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen client->input = i_stream_create_fd(client->fd, LOGIN_MAX_INBUF_SIZE);
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen client->output = o_stream_create_fd(client->fd, LOGIN_MAX_OUTBUF_SIZE);
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen o_stream_set_no_error_handling(client->output, TRUE);
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen if (login_rawlog_dir != NULL) {
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen if (iostream_rawlog_create(login_rawlog_dir, &client->input,
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen &client->output) < 0)
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen login_rawlog_dir = NULL;
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen }
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen}
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainenstatic bool client_is_trusted(struct client *client)
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen{
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen const char *const *net;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen struct ip_addr net_ip;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen unsigned int bits;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen if (client->set->login_trusted_networks == NULL)
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen return FALSE;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen net = t_strsplit_spaces(client->set->login_trusted_networks, ", ");
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen for (; *net != NULL; net++) {
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen if (net_parse_range(*net, &net_ip, &bits) < 0) {
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen i_error("login_trusted_networks: "
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen "Invalid network '%s'", *net);
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen break;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen }
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen if (net_is_in_network(&client->ip, &net_ip, bits))
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen return TRUE;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen }
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen return FALSE;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen}
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainenstruct client *
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainenclient_alloc(int fd, pool_t pool,
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen const struct master_service_connection *conn,
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen const struct login_settings *set,
7c95b03620a03a43dd72d39608cea5fc77393ad6Timo Sirainen const struct master_service_ssl_settings *ssl_set)
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen{
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen struct client *client;
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen i_assert(fd != -1);
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen client = login_binary->client_vfuncs->alloc(pool);
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen client->v = *login_binary->client_vfuncs;
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen if (client->v.auth_send_challenge == NULL)
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen client->v.auth_send_challenge = client_auth_send_challenge;
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen if (client->v.auth_parse_response == NULL)
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen client->v.auth_parse_response = client_auth_parse_response;
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen client->created = ioloop_time;
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen client->refcount = 1;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen client->pool = pool;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen client->preproxy_pool = pool_alloconly_create(MEMPOOL_GROWING"preproxy pool", 256);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen client->set = set;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen client->ssl_set = ssl_set;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen p_array_init(&client->module_contexts, client->pool, 5);
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen
7c95b03620a03a43dd72d39608cea5fc77393ad6Timo Sirainen client->fd = fd;
7c95b03620a03a43dd72d39608cea5fc77393ad6Timo Sirainen client->local_ip = conn->local_ip;
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen client->local_port = conn->local_port;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen client->ip = conn->remote_ip;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen client->remote_port = conn->remote_port;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen client->real_local_ip = conn->real_local_ip;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen client->real_local_port = conn->real_local_port;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen client->real_remote_ip = conn->real_remote_ip;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen client->real_remote_port = conn->real_remote_port;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen client->listener_name = p_strdup(client->pool, conn->name);
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen client->trusted = client_is_trusted(client);
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen if (conn->proxied) {
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen client->secured = conn->proxy.ssl || client->trusted;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen client->local_name = conn->proxy.hostname;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen client->client_cert_common_name = conn->proxy.cert_common_name;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen } else {
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen client->secured = client->trusted ||
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen net_ip_compare(&conn->real_remote_ip, &conn->real_local_ip);
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen }
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen client->proxy_ttl = LOGIN_PROXY_TTL;
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen return client;
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen}
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainenvoid client_init(struct client *client, void **other_sets)
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen{
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen if (last_client == NULL)
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen last_client = client;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen DLLIST_PREPEND(&clients, client);
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen clients_count++;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen client->to_disconnect =
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen timeout_add(CLIENT_LOGIN_TIMEOUT_MSECS,
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen client_idle_disconnect_timeout, client);
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen client_open_streams(client);
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen hook_login_client_allocated(client);
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen client->v.create(client, other_sets);
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen client->create_finished = TRUE;
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen if (auth_client_is_connected(auth_client))
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen client_notify_auth_ready(client);
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen else
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen client_set_auth_waiting(client);
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen login_refresh_proctitle();
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen}
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainenvoid client_destroy(struct client *client, const char *reason)
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen{
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen i_assert(client->create_finished);
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen if (client->destroyed)
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen return;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen client->destroyed = TRUE;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen pool_unref(&client->preproxy_pool);
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen if (!client->login_success &&
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen !client->no_extra_disconnect_reason && reason != NULL) {
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen const char *extra_reason =
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen client_get_extra_disconnect_reason(client);
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen if (extra_reason[0] != '\0')
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen reason = t_strconcat(reason, " ", extra_reason, NULL);
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen }
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen if (reason != NULL)
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen client_log(client, reason);
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen if (last_client == client)
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen last_client = client->prev;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen DLLIST_REMOVE(&clients, client);
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen if (client->output != NULL)
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen o_stream_uncork(client->output);
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen if (!client->login_success) {
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen io_remove(&client->io);
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen if (client->ssl_proxy != NULL)
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen ssl_proxy_destroy(client->ssl_proxy);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (client->iostream_fd_proxy != NULL)
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen iostream_proxy_unref(&client->iostream_fd_proxy);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_stream_close(client->input);
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen o_stream_close(client->output);
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen i_close_fd(&client->fd);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else {
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen /* Login was successful. We may now be proxying the connection,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen so don't disconnect the client until client_unref(). */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (client->iostream_fd_proxy != NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client->fd_proxying = TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen DLLIST_PREPEND(&client_fd_proxies, client);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client_fd_proxies_count++;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (client->master_tag != 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(client->auth_request == NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(client->authenticating);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(client->refcount > 1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client->authenticating = FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen master_auth_request_abort(master_auth, client->master_tag);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client->refcount--;
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen } else if (client->auth_request != NULL) {
8830fab191cab8440281eb641dfdd93974b2933bTimo Sirainen i_assert(client->authenticating);
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen sasl_server_auth_abort(client);
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen } else {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(!client->authenticating);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
92888ef30960c30ccc9e030fe7eab5d4d04a7d1cTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen timeout_remove(&client->to_disconnect);
92888ef30960c30ccc9e030fe7eab5d4d04a7d1cTimo Sirainen timeout_remove(&client->to_auth_waiting);
92888ef30960c30ccc9e030fe7eab5d4d04a7d1cTimo Sirainen if (client->auth_response != NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen str_free(&client->auth_response);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (client->proxy_password != NULL) {
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen safe_memset(client->proxy_password, 0,
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen strlen(client->proxy_password));
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen i_free_and_null(client->proxy_password);
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen }
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen if (client->proxy_sasl_client != NULL)
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen dsasl_client_free(&client->proxy_sasl_client);
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen if (client->login_proxy != NULL)
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen login_proxy_free(&client->login_proxy);
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen if (client->v.destroy != NULL)
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen client->v.destroy(client);
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen if (client_unref(&client) && initial_service_count == 1) {
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen /* as soon as this connection is done with proxying
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen (or whatever), the process will die. there's no need for
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen authentication anymore, so close the connection.
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen do this only with initial service_count=1, in case there
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen are other clients with pending authentications */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen auth_client_disconnect(auth_client, "unnecessary connection");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
d482b35af87f5fd872bad007da0475813a401a49Timo Sirainen login_client_destroyed();
d482b35af87f5fd872bad007da0475813a401a49Timo Sirainen login_refresh_proctitle();
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid client_destroy_success(struct client *client, const char *reason)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client->login_success = TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client_destroy(client, reason);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid client_ref(struct client *client)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen client->refcount++;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenbool client_unref(struct client **_client)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct client *client = *_client;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen *_client = NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen i_assert(client->refcount > 0);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (--client->refcount > 0)
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen return TRUE;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen if (!client->create_finished) {
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen pool_unref(&client->preproxy_pool);
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen pool_unref(&client->pool);
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen return FALSE;
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen }
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen i_assert(client->destroyed);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(client->login_proxy == NULL);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen if (client->v.free != NULL)
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen client->v.free(client);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen if (client->ssl_proxy != NULL)
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen ssl_proxy_free(&client->ssl_proxy);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen if (client->iostream_fd_proxy != NULL)
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen iostream_proxy_unref(&client->iostream_fd_proxy);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen if (client->fd_proxying) {
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen DLLIST_REMOVE(&client_fd_proxies, client);
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen i_assert(client_fd_proxies_count > 0);
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen client_fd_proxies_count--;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_stream_unref(&client->input);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen o_stream_unref(&client->output);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen i_close_fd(&client->fd);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_free(client->proxy_user);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen i_free(client->proxy_master_user);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen i_free(client->virtual_user);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen i_free(client->virtual_user_orig);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen i_free(client->virtual_auth_user);
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen i_free(client->auth_mech_name);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen i_free(client->master_data_prefix);
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen pool_unref(&client->pool);
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(clients_count > 0);
3c24d47ad5ff02ea00684233bef314ef2eefda4aTimo Sirainen clients_count--;
3c24d47ad5ff02ea00684233bef314ef2eefda4aTimo Sirainen
3c24d47ad5ff02ea00684233bef314ef2eefda4aTimo Sirainen master_service_client_connection_destroyed(master_service);
3c24d47ad5ff02ea00684233bef314ef2eefda4aTimo Sirainen login_refresh_proctitle();
3c24d47ad5ff02ea00684233bef314ef2eefda4aTimo Sirainen return FALSE;
3c24d47ad5ff02ea00684233bef314ef2eefda4aTimo Sirainen}
3c24d47ad5ff02ea00684233bef314ef2eefda4aTimo Sirainen
4c1827d5d718d6f610df3209a2eb95a6591698afTimo Sirainenvoid client_common_default_free(struct client *client ATTR_UNUSED)
5a4ab3d6e108a899c8b51bebd0094a37b738d5a1Timo Sirainen{
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen}
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainenvoid client_destroy_oldest(void)
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen{
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen struct client *client;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (last_client == NULL) {
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen /* we have no clients */
91b5eae18db48ebb70eee5407a7ab52bf798ee12Timo Sirainen return;
91b5eae18db48ebb70eee5407a7ab52bf798ee12Timo Sirainen }
91b5eae18db48ebb70eee5407a7ab52bf798ee12Timo Sirainen
91b5eae18db48ebb70eee5407a7ab52bf798ee12Timo Sirainen /* destroy the last client that hasn't successfully authenticated yet.
91b5eae18db48ebb70eee5407a7ab52bf798ee12Timo Sirainen this is usually the last client, but don't kill it if it's just
91b5eae18db48ebb70eee5407a7ab52bf798ee12Timo Sirainen waiting for master to finish its job. */
91b5eae18db48ebb70eee5407a7ab52bf798ee12Timo Sirainen for (client = last_client; client != NULL; client = client->prev) {
91b5eae18db48ebb70eee5407a7ab52bf798ee12Timo Sirainen if (client->master_tag == 0)
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen break;
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen }
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen if (client == NULL)
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen client = last_client;
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen client_notify_disconnect(client, CLIENT_DISCONNECT_RESOURCE_CONSTRAINT,
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen "Connection queue full");
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen client_destroy(client, "Disconnected: Connection queue full");
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen}
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainenvoid clients_destroy_all_reason(const char *reason)
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen{
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen struct client *client, *next;
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen for (client = clients; client != NULL; client = next) {
cd65dfcedc603fabbf644be793efb09096f6c1b5Timo Sirainen next = client->next;
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen client_notify_disconnect(client,
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen CLIENT_DISCONNECT_SYSTEM_SHUTDOWN, reason);
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen client_destroy(client, reason);
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen }
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen}
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainenvoid clients_destroy_all(void)
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen{
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen clients_destroy_all_reason("Disconnected: Shutting down");
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen}
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainenint client_init_ssl(struct client *client)
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen{
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen int fd_ssl;
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen i_assert(client->fd != -1);
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen fd_ssl = ssl_proxy_alloc(client->fd, &client->ip, client->pool,
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen client->set, client->ssl_set,
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen &client->ssl_proxy);
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen if (fd_ssl == -1)
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen return -1;
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen ssl_proxy_set_client(client->ssl_proxy, client);
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen ssl_proxy_start(client->ssl_proxy);
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen client->tls = TRUE;
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen client->secured = TRUE;
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen client->fd = fd_ssl;
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen return 0;
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen}
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainenstatic void client_start_tls(struct client *client)
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen{
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen if (client_init_ssl(client) < 0) {
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen client_notify_disconnect(client,
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen CLIENT_DISCONNECT_INTERNAL_ERROR,
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen "TLS initialization failed.");
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen client_destroy(client,
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen "Disconnected: TLS initialization failed.");
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen return;
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen }
28dd1eeb9fdb93051bb5899c80cf300d69ba9f9eTimo Sirainen
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen client->starttls = TRUE;
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen login_refresh_proctitle();
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen
4c1827d5d718d6f610df3209a2eb95a6591698afTimo Sirainen client->io = io_add(client->fd, IO_READ, client_input, client);
4c1827d5d718d6f610df3209a2eb95a6591698afTimo Sirainen i_stream_unref(&client->input);
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen o_stream_unref(&client->output);
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen client_open_streams(client);
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
05751847e5e493fecfd0634d35d21722aad44a0bTimo Sirainen client->v.starttls(client);
91b5eae18db48ebb70eee5407a7ab52bf798ee12Timo Sirainen}
91b5eae18db48ebb70eee5407a7ab52bf798ee12Timo Sirainen
91b5eae18db48ebb70eee5407a7ab52bf798ee12Timo Sirainenstatic int client_output_starttls(struct client *client)
91b5eae18db48ebb70eee5407a7ab52bf798ee12Timo Sirainen{
91b5eae18db48ebb70eee5407a7ab52bf798ee12Timo Sirainen int ret;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen if ((ret = o_stream_flush(client->output)) < 0) {
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen client_destroy(client, "Disconnected");
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen return 1;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen }
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen if (ret > 0) {
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen o_stream_unset_flush_callback(client->output);
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen client_start_tls(client);
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen }
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen return 1;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen}
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainenvoid client_cmd_starttls(struct client *client)
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen{
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen if (client->tls) {
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen client->v.notify_starttls(client, FALSE, "TLS is already active.");
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen return;
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen }
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen if (!client_is_tls_enabled(client)) {
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen client->v.notify_starttls(client, FALSE, "TLS support isn't enabled.");
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen return;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen }
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen /* remove input handler, SSL proxy gives us a new fd. we also have to
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen remove it in case we have to wait for buffer to be flushed */
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen io_remove(&client->io);
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen client->v.notify_starttls(client, TRUE, "Begin TLS negotiation now.");
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen /* uncork the old fd */
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen o_stream_uncork(client->output);
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen if (o_stream_flush(client->output) <= 0) {
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen /* the buffer has to be flushed */
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen o_stream_set_flush_pending(client->output, TRUE);
28dd1eeb9fdb93051bb5899c80cf300d69ba9f9eTimo Sirainen o_stream_set_flush_callback(client->output,
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen client_output_starttls, client);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen } else {
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen client_start_tls(client);
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen }
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen}
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainenstatic void
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Siraineniostream_fd_proxy_finished(enum iostream_proxy_side side ATTR_UNUSED,
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen enum iostream_proxy_status status ATTR_UNUSED,
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen struct client *client)
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen{
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen /* Destroy the proxy now. The other side of the proxy is still
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen unfinished and we don't want to get back here and unreference
b47c57ee07ccfe76cc23b23bc720e17fe9a46d5cTimo Sirainen the client twice. */
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen iostream_proxy_unref(&client->iostream_fd_proxy);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen client_unref(&client);
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen}
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainenint client_get_plaintext_fd(struct client *client, int *fd_r, bool *close_fd_r)
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen{
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen int fds[2];
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen if (!client->tls) {
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen /* Plaintext connection - We can send the fd directly to
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen the post-login process without any proxying. */
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen *fd_r = client->fd;
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen *close_fd_r = FALSE;
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen return 0;
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen }
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen /* We'll have to start proxying from now on until either side
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen disconnects. Create a socketpair where login process is proxying on
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen one side and the other side is sent to the post-login process. */
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) {
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen client_log_err(client, t_strdup_printf("socketpair() failed: %m"));
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen return -1;
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen }
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen fd_set_nonblock(fds[0], TRUE);
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen fd_set_nonblock(fds[1], TRUE);
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen struct ostream *output = o_stream_create_fd(fds[0], IO_BLOCK_SIZE);
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen struct istream *input =
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen i_stream_create_fd_autoclose(&fds[0], IO_BLOCK_SIZE);
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen o_stream_set_no_error_handling(output, TRUE);
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen i_assert(client->io == NULL);
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen client_ref(client);
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen client->iostream_fd_proxy =
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen iostream_proxy_create(input, output,
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen client->input, client->output);
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen i_stream_unref(&input);
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen o_stream_unref(&output);
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen iostream_proxy_set_completion_callback(client->iostream_fd_proxy,
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen iostream_fd_proxy_finished,
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen client);
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen iostream_proxy_start(client->iostream_fd_proxy);
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen *fd_r = fds[1];
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen *close_fd_r = TRUE;
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen return 0;
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen}
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainenunsigned int clients_get_count(void)
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen{
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen return clients_count;
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen}
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainenunsigned int clients_get_fd_proxies_count(void)
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen{
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen return client_fd_proxies_count;
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen}
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainenstruct client *clients_get_first_fd_proxy(void)
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen{
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen return client_fd_proxies;
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen}
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainenvoid client_add_forward_field(struct client *client, const char *key,
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen const char *value)
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen{
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen if (client->forward_fields == NULL)
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen client->forward_fields = str_new(client->preproxy_pool, 32);
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen else
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen str_append_c(client->forward_fields, '\t');
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen /* prefixing is done by auth process */
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen str_append_tabescaped(client->forward_fields, key);
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen str_append_c(client->forward_fields, '=');
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen str_append_tabescaped(client->forward_fields, value);
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen}
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainenconst char *client_get_session_id(struct client *client)
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen{
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen buffer_t *buf, *base64_buf;
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen struct timeval tv;
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen uint64_t timestamp;
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen unsigned int i;
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen if (client->session_id != NULL)
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen return client->session_id;
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen buf = buffer_create_dynamic(pool_datastack_create(), 24);
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen base64_buf = buffer_create_dynamic(pool_datastack_create(), 24*2);
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen if (gettimeofday(&tv, NULL) < 0)
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen i_fatal("gettimeofday(): %m");
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen timestamp = tv.tv_usec + (long long)tv.tv_sec * 1000ULL*1000ULL;
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen /* add lowest 48 bits of the timestamp. this gives us a bit less than
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen 9 years until it wraps */
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen for (i = 0; i < 48; i += 8)
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen buffer_append_c(buf, (timestamp >> i) & 0xff);
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen buffer_append_c(buf, client->remote_port & 0xff);
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen buffer_append_c(buf, (client->remote_port >> 8) & 0xff);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen if (IPADDR_IS_V6(&client->ip))
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen buffer_append(buf, &client->ip.u.ip6, sizeof(client->ip.u.ip6));
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen else
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen buffer_append(buf, &client->ip.u.ip4, sizeof(client->ip.u.ip4));
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen base64_encode(buf->data, buf->used, base64_buf);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen client->session_id = p_strdup(client->pool, str_c(base64_buf));
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen return client->session_id;
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen}
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainenstatic struct var_expand_table login_var_expand_empty_tab[] = {
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen { 'u', NULL, "user" },
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen { 'n', NULL, "username" },
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen { 'd', NULL, "domain" },
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen { 's', NULL, "service" },
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen { 'h', NULL, "home" },
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen { 'l', NULL, "lip" },
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen { 'r', NULL, "rip" },
e4fb5bfcdff32d337d054cce36e00e1cdfaae9f8Timo Sirainen { 'p', NULL, "pid" },
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen { 'm', NULL, "mech" },
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen { 'a', NULL, "lport" },
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen { 'b', NULL, "rport" },
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen { 'c', NULL, "secured" },
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen { 'k', NULL, "ssl_security" },
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen { 'e', NULL, "mail_pid" },
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen { '\0', NULL, "session" },
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen { '\0', NULL, "real_lip" },
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen { '\0', NULL, "real_rip" },
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen { '\0', NULL, "real_lport" },
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen { '\0', NULL, "real_rport" },
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen { '\0', NULL, "orig_user" },
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen { '\0', NULL, "orig_username" },
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen { '\0', NULL, "orig_domain" },
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen { '\0', NULL, "auth_user" },
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen { '\0', NULL, "auth_username" },
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen { '\0', NULL, "auth_domain" },
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen { '\0', NULL, "listener" },
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen { '\0', NULL, "local_name" },
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen { '\0', NULL, NULL }
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen};
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainenstatic void
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainenget_var_expand_users(struct var_expand_table *tab, const char *user)
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen{
e2ea49bd487d76b425e270321e9cf1e546642de0Timo Sirainen unsigned int i;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
19593623a2278039be23fc93e3404c012920b664Timo Sirainen tab[0].value = user;
19593623a2278039be23fc93e3404c012920b664Timo Sirainen tab[1].value = t_strcut(user, '@');
e2ea49bd487d76b425e270321e9cf1e546642de0Timo Sirainen tab[2].value = i_strchr_to_next(user, '@');
e2ea49bd487d76b425e270321e9cf1e546642de0Timo Sirainen
e2ea49bd487d76b425e270321e9cf1e546642de0Timo Sirainen for (i = 0; i < 3; i++)
e2ea49bd487d76b425e270321e9cf1e546642de0Timo Sirainen tab[i].value = str_sanitize(tab[i].value, 80);
e2ea49bd487d76b425e270321e9cf1e546642de0Timo Sirainen}
e2ea49bd487d76b425e270321e9cf1e546642de0Timo Sirainen
e2ea49bd487d76b425e270321e9cf1e546642de0Timo Sirainenstatic const struct var_expand_table *
e2ea49bd487d76b425e270321e9cf1e546642de0Timo Sirainenget_var_expand_table(struct client *client)
e2ea49bd487d76b425e270321e9cf1e546642de0Timo Sirainen{
e2ea49bd487d76b425e270321e9cf1e546642de0Timo Sirainen struct var_expand_table *tab;
e2ea49bd487d76b425e270321e9cf1e546642de0Timo Sirainen
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen tab = t_malloc_no0(sizeof(login_var_expand_empty_tab));
e2ea49bd487d76b425e270321e9cf1e546642de0Timo Sirainen memcpy(tab, login_var_expand_empty_tab,
e2ea49bd487d76b425e270321e9cf1e546642de0Timo Sirainen sizeof(login_var_expand_empty_tab));
e2ea49bd487d76b425e270321e9cf1e546642de0Timo Sirainen
e2ea49bd487d76b425e270321e9cf1e546642de0Timo Sirainen if (client->virtual_user != NULL)
e2ea49bd487d76b425e270321e9cf1e546642de0Timo Sirainen get_var_expand_users(tab, client->virtual_user);
e2ea49bd487d76b425e270321e9cf1e546642de0Timo Sirainen tab[3].value = login_binary->protocol;
e2ea49bd487d76b425e270321e9cf1e546642de0Timo Sirainen tab[4].value = getenv("HOME");
e2ea49bd487d76b425e270321e9cf1e546642de0Timo Sirainen tab[5].value = net_ip2addr(&client->local_ip);
e2ea49bd487d76b425e270321e9cf1e546642de0Timo Sirainen tab[6].value = net_ip2addr(&client->ip);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen tab[7].value = my_pid;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen tab[8].value = client->auth_mech_name == NULL ? NULL :
e2ea49bd487d76b425e270321e9cf1e546642de0Timo Sirainen str_sanitize(client->auth_mech_name, MAX_MECH_NAME);
e2ea49bd487d76b425e270321e9cf1e546642de0Timo Sirainen tab[9].value = dec2str(client->local_port);
e2ea49bd487d76b425e270321e9cf1e546642de0Timo Sirainen tab[10].value = dec2str(client->remote_port);
e2ea49bd487d76b425e270321e9cf1e546642de0Timo Sirainen if (!client->tls) {
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen tab[11].value = client->secured ? "secured" : NULL;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen tab[12].value = "";
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen } else {
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen const char *ssl_state =
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen ssl_proxy_is_handshaked(client->ssl_proxy) ?
e2ea49bd487d76b425e270321e9cf1e546642de0Timo Sirainen "TLS" : "TLS handshaking";
e2ea49bd487d76b425e270321e9cf1e546642de0Timo Sirainen const char *ssl_error =
c48140ca508ebc9642737e7fd6c8d9e52f95df32Timo Sirainen ssl_proxy_get_last_error(client->ssl_proxy);
c48140ca508ebc9642737e7fd6c8d9e52f95df32Timo Sirainen
c48140ca508ebc9642737e7fd6c8d9e52f95df32Timo Sirainen tab[11].value = ssl_error == NULL ? ssl_state :
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen t_strdup_printf("%s: %s", ssl_state, ssl_error);
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen tab[12].value =
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen ssl_proxy_get_security_string(client->ssl_proxy);
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen }
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen tab[13].value = client->mail_pid == 0 ? "" :
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen dec2str(client->mail_pid);
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen tab[14].value = client_get_session_id(client);
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen tab[15].value = net_ip2addr(&client->real_local_ip);
c48140ca508ebc9642737e7fd6c8d9e52f95df32Timo Sirainen tab[16].value = net_ip2addr(&client->real_remote_ip);
c48140ca508ebc9642737e7fd6c8d9e52f95df32Timo Sirainen tab[17].value = dec2str(client->real_local_port);
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen tab[18].value = dec2str(client->real_remote_port);
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen if (client->virtual_user_orig != NULL)
c48140ca508ebc9642737e7fd6c8d9e52f95df32Timo Sirainen get_var_expand_users(tab+19, client->virtual_user_orig);
c48140ca508ebc9642737e7fd6c8d9e52f95df32Timo Sirainen else {
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen tab[19].value = tab[0].value;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen tab[20].value = tab[1].value;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen tab[21].value = tab[2].value;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen }
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen if (client->virtual_auth_user != NULL)
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen get_var_expand_users(tab+22, client->virtual_auth_user);
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen else {
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen tab[22].value = tab[19].value;
3c24d47ad5ff02ea00684233bef314ef2eefda4aTimo Sirainen tab[23].value = tab[20].value;
19593623a2278039be23fc93e3404c012920b664Timo Sirainen tab[24].value = tab[21].value;
19593623a2278039be23fc93e3404c012920b664Timo Sirainen }
19593623a2278039be23fc93e3404c012920b664Timo Sirainen tab[25].value = client->listener_name;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen tab[26].value = str_sanitize(client->local_name, 256);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return tab;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic bool have_username_key(const char *str)
3e4bbbceed7882b8dab558aa90913a491eb15cc6Timo Sirainen{
3e4bbbceed7882b8dab558aa90913a491eb15cc6Timo Sirainen char key;
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen for (; *str != '\0'; str++) {
3e4bbbceed7882b8dab558aa90913a491eb15cc6Timo Sirainen if (str[0] == '%' && str[1] != '\0') {
3e4bbbceed7882b8dab558aa90913a491eb15cc6Timo Sirainen str++;
3e4bbbceed7882b8dab558aa90913a491eb15cc6Timo Sirainen key = var_get_key(str);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (key == 'u' || key == 'n')
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return TRUE;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen return FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic int
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenclient_var_expand_func_passdb(const char *data, void *context,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const char **value_r,
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen const char **error_r ATTR_UNUSED)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct client *client = context;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const char *field_name = data;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int i;
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen size_t field_name_len;
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *value_r = NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen if (client->auth_passdb_args == NULL)
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen return 1;
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen field_name_len = strlen(field_name);
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen for (i = 0; client->auth_passdb_args[i] != NULL; i++) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (strncmp(client->auth_passdb_args[i], field_name,
7b524faf719c9998dd586708d6ee0faa307a6c02Timo Sirainen field_name_len) == 0 &&
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen client->auth_passdb_args[i][field_name_len] == '=') {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *value_r = client->auth_passdb_args[i] + field_name_len+1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen return 1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic const char *
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainenclient_get_log_str(struct client *client, const char *msg)
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen{
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen static const struct var_expand_func_table func_table[] = {
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen { "passdb", client_var_expand_func_passdb },
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen { NULL, NULL }
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen };
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen static bool expand_error_logged = FALSE;
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen const struct var_expand_table *var_expand_table;
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen char *const *e;
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen const char *error;
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen string_t *str, *str2;
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen unsigned int pos;
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen var_expand_table = get_var_expand_table(client);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen str = t_str_new(256);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen str2 = t_str_new(128);
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen for (e = client->set->log_format_elements_split; *e != NULL; e++) {
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen pos = str_len(str);
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen if (var_expand_with_funcs(str, *e, var_expand_table,
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen func_table, client, &error) <= 0 &&
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen !expand_error_logged) {
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen i_error("Failed to expand log_format_elements=%s: %s",
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen *e, error);
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen expand_error_logged = TRUE;
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen }
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen if (have_username_key(*e)) {
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen /* username is added even if it's empty */
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen } else {
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen str_truncate(str2, 0);
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen if (var_expand(str2, *e, login_var_expand_empty_tab,
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen &error) <= 0) {
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen /* we just logged this error above. no need
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen to do it again. */
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen }
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen if (strcmp(str_c(str)+pos, str_c(str2)) == 0) {
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen /* empty %variables, don't add */
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen str_truncate(str, pos);
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen continue;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen }
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen }
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen if (str_len(str) > 0)
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen str_append(str, ", ");
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen }
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen if (str_len(str) > 0)
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen str_truncate(str, str_len(str)-2);
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen const struct var_expand_table tab[3] = {
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen { 's', t_strdup(str_c(str)), NULL },
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen { '$', msg, NULL },
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen { '\0', NULL, NULL }
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen };
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen str_truncate(str, 0);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (var_expand(str, client->set->login_log_format, tab, &error) <= 0) {
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen i_error("Failed to expand login_log_format=%s: %s",
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen client->set->login_log_format, error);
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen expand_error_logged = TRUE;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen }
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen return str_c(str);
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen}
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainenvoid client_log(struct client *client, const char *msg)
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen{
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen T_BEGIN {
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen i_info("%s", client_get_log_str(client, msg));
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen } T_END;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen}
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainenvoid client_log_err(struct client *client, const char *msg)
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen{
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen T_BEGIN {
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen i_error("%s", client_get_log_str(client, msg));
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen } T_END;
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen}
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainenvoid client_log_warn(struct client *client, const char *msg)
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen{
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen T_BEGIN {
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen i_warning("%s", client_get_log_str(client, msg));
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen } T_END;
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen}
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainenbool client_is_tls_enabled(struct client *client)
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen{
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen return ssl_initialized && strcmp(client->ssl_set->ssl, "no") != 0;
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen}
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainenconst char *client_get_extra_disconnect_reason(struct client *client)
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen{
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen unsigned int auth_secs = client->auth_first_started == 0 ? 0 :
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen ioloop_time - client->auth_first_started;
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen if (client->set->auth_ssl_require_client_cert &&
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen client->ssl_proxy != NULL) {
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen if (ssl_proxy_has_broken_client_cert(client->ssl_proxy))
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen return "(client sent an invalid cert)";
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen if (!ssl_proxy_has_valid_client_cert(client->ssl_proxy))
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen return "(client didn't send a cert)";
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen }
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen if (!client->notified_auth_ready)
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen return t_strdup_printf(
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen "(disconnected before auth was ready, waited %u secs)",
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen (unsigned int)(ioloop_time - client->created));
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen if (client->auth_attempts == 0) {
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen if (!client->banner_sent) {
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen /* disconnected by a plugin */
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen return "";
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen }
c9f1a617593eb569fb02f45041bad3c13e534496Timo Sirainen return t_strdup_printf("(no auth attempts in %u secs)",
c9f1a617593eb569fb02f45041bad3c13e534496Timo Sirainen (unsigned int)(ioloop_time - client->created));
c9f1a617593eb569fb02f45041bad3c13e534496Timo Sirainen }
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen
c9f1a617593eb569fb02f45041bad3c13e534496Timo Sirainen /* some auth attempts without SSL/TLS */
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen if (client->set->auth_ssl_require_client_cert &&
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen client->ssl_proxy == NULL)
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen return "(cert required, client didn't start TLS)";
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen if (client->auth_waiting && client->auth_attempts == 1) {
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen return t_strdup_printf("(client didn't finish SASL auth, "
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen "waited %u secs)", auth_secs);
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen }
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen if (client->auth_request != NULL && client->auth_attempts == 1) {
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen return t_strdup_printf("(disconnected while authenticating, "
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen "waited %u secs)", auth_secs);
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen }
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen if (client->authenticating && client->auth_attempts == 1) {
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen return t_strdup_printf("(disconnected while finishing login, "
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen "waited %u secs)", auth_secs);
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen }
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen if (client->auth_try_aborted && client->auth_attempts == 1)
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen return "(aborted authentication)";
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen if (client->auth_process_comm_fail)
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen return "(auth process communication failure)";
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen if (client->proxy_auth_failed)
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen return "(proxy dest auth failed)";
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen if (client->auth_successes > 0) {
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen return t_strdup_printf("(internal failure, %u successful auths)",
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen client->auth_successes);
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen }
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen switch (client->last_auth_fail) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen case CLIENT_AUTH_FAIL_CODE_AUTHZFAILED:
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen return t_strdup_printf(
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "(authorization failed, %u attempts in %u secs)",
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client->auth_attempts, auth_secs);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen case CLIENT_AUTH_FAIL_CODE_TEMPFAIL:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return "(auth service reported temporary failure)";
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen case CLIENT_AUTH_FAIL_CODE_USER_DISABLED:
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen return "(user disabled)";
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen case CLIENT_AUTH_FAIL_CODE_PASS_EXPIRED:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return "(password expired)";
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen case CLIENT_AUTH_FAIL_CODE_INVALID_BASE64:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return "(sent invalid base64 in response)";
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen case CLIENT_AUTH_FAIL_CODE_LOGIN_DISABLED:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return "(login disabled)";
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen case CLIENT_AUTH_FAIL_CODE_MECH_INVALID:
d22390f33eedbd2413debabc0662dde5241b1aa6Timo Sirainen return "(tried to use unsupported auth mechanism)";
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen case CLIENT_AUTH_FAIL_CODE_MECH_SSL_REQUIRED:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return "(tried to use disallowed plaintext auth)";
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen default:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen break;
d22390f33eedbd2413debabc0662dde5241b1aa6Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
d22390f33eedbd2413debabc0662dde5241b1aa6Timo Sirainen return t_strdup_printf("(auth failed, %u attempts in %u secs)",
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client->auth_attempts, auth_secs);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
d22390f33eedbd2413debabc0662dde5241b1aa6Timo Sirainenvoid client_notify_disconnect(struct client *client,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen enum client_disconnect_reason reason,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const char *text)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (!client->notified_disconnect) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (client->v.notify_disconnect != NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client->v.notify_disconnect(client, reason, text);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client->notified_disconnect = TRUE;
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen }
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid client_notify_auth_ready(struct client *client)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (!client->notified_auth_ready) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (client->v.notify_auth_ready != NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client->v.notify_auth_ready(client);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client->notified_auth_ready = TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainenvoid client_notify_status(struct client *client, bool bad, const char *text)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (client->v.notify_status != NULL)
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen client->v.notify_status(client, bad, text);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid client_common_send_raw_data(struct client *client,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const void *data, size_t size)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ssize_t ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ret = o_stream_send(client->output, data, size);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ret < 0 || (size_t)ret != size) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* either disconnection or buffer full. in either case we want
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen this connection destroyed. however destroying it here might
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen break things if client is still tried to be accessed without
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen being referenced.. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_stream_close(client->input);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid client_send_raw_data(struct client *client, const void *data, size_t size)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client->v.send_raw_data(client, data, size);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid client_send_raw(struct client *client, const char *data)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client_send_raw_data(client, data, strlen(data));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
86bc22621dcce6d9f1ca7216c9cc958381a61277Timo Sirainen
86bc22621dcce6d9f1ca7216c9cc958381a61277Timo Sirainenbool client_read(struct client *client)
86bc22621dcce6d9f1ca7216c9cc958381a61277Timo Sirainen{
86bc22621dcce6d9f1ca7216c9cc958381a61277Timo Sirainen switch (i_stream_read(client->input)) {
86bc22621dcce6d9f1ca7216c9cc958381a61277Timo Sirainen case -2:
86bc22621dcce6d9f1ca7216c9cc958381a61277Timo Sirainen /* buffer full */
86bc22621dcce6d9f1ca7216c9cc958381a61277Timo Sirainen client_notify_disconnect(client,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen CLIENT_DISCONNECT_RESOURCE_CONSTRAINT,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "Input buffer full, aborting");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client_destroy(client, "Disconnected: Input buffer full");
86bc22621dcce6d9f1ca7216c9cc958381a61277Timo Sirainen return FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen case -1:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* disconnected */
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen client_destroy(client, "Disconnected");
e687badfdd7f4001e9a89a80a2c4a79ec4bafc8dTimo Sirainen return FALSE;
e687badfdd7f4001e9a89a80a2c4a79ec4bafc8dTimo Sirainen case 0:
e687badfdd7f4001e9a89a80a2c4a79ec4bafc8dTimo Sirainen /* nothing new read */
e687badfdd7f4001e9a89a80a2c4a79ec4bafc8dTimo Sirainen return TRUE;
e687badfdd7f4001e9a89a80a2c4a79ec4bafc8dTimo Sirainen default:
e687badfdd7f4001e9a89a80a2c4a79ec4bafc8dTimo Sirainen /* something was read */
e687badfdd7f4001e9a89a80a2c4a79ec4bafc8dTimo Sirainen return TRUE;
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen }
e687badfdd7f4001e9a89a80a2c4a79ec4bafc8dTimo Sirainen}
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainenvoid client_input(struct client *client)
e687badfdd7f4001e9a89a80a2c4a79ec4bafc8dTimo Sirainen{
e687badfdd7f4001e9a89a80a2c4a79ec4bafc8dTimo Sirainen client->v.input(client);
e687badfdd7f4001e9a89a80a2c4a79ec4bafc8dTimo Sirainen}
e687badfdd7f4001e9a89a80a2c4a79ec4bafc8dTimo Sirainen
e687badfdd7f4001e9a89a80a2c4a79ec4bafc8dTimo Sirainenvoid client_common_init(void)
e687badfdd7f4001e9a89a80a2c4a79ec4bafc8dTimo Sirainen{
e687badfdd7f4001e9a89a80a2c4a79ec4bafc8dTimo Sirainen i_array_init(&module_hooks, 32);
e687badfdd7f4001e9a89a80a2c4a79ec4bafc8dTimo Sirainen}
e687badfdd7f4001e9a89a80a2c4a79ec4bafc8dTimo Sirainen
e687badfdd7f4001e9a89a80a2c4a79ec4bafc8dTimo Sirainenvoid client_destroy_fd_proxies(void)
e687badfdd7f4001e9a89a80a2c4a79ec4bafc8dTimo Sirainen{
e687badfdd7f4001e9a89a80a2c4a79ec4bafc8dTimo Sirainen while (client_fd_proxies != NULL) {
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen struct client *client = client_fd_proxies;
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen client_unref(&client);
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(client_fd_proxies_count == 0);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen}
40ef82c46f6652412b068ebcdac7c3e74840a284Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid client_common_deinit(void)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
40ef82c46f6652412b068ebcdac7c3e74840a284Timo Sirainen array_free(&module_hooks);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen