client-common.c revision c7eb1ffb7c73cb5d9c1316bbecd02947441a40d4
5a580c3a38ced62d4bcc95b8ac7c4f2935b5d294Timo Sirainen/* Copyright (c) 2002-2013 Dovecot authors, see the included COPYING file */
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen#include "login-common.h"
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen#include "hostpid.h"
70ead6466f9baa8294e71fc2fba0a4f54f488b5eTimo Sirainen#include "llist.h"
bdd36cfdba3ff66d25570a9ff568d69e1eb543cfTimo Sirainen#include "istream.h"
dd7cbb32412c2f4d2d223af66672535bc1237246Timo Sirainen#include "ostream.h"
57f5683fd9dc9bc79816c418bb30fdbc33b68a8cTimo Sirainen#include "iostream-rawlog.h"
306b3f41b05da642d87e7ca7a1496efce9f5902fTimo Sirainen#include "process-title.h"
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen#include "buffer.h"
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen#include "str.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "base64.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "str-sanitize.h"
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen#include "safe-memset.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "var-expand.h"
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainen#include "master-interface.h"
9fd2181788a61500641c66aec0f8c746b19bf830Timo Sirainen#include "master-service.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "master-service-ssl-settings.h"
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen#include "master-auth.h"
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen#include "auth-client.h"
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen#include "dsasl-client.h"
70ead6466f9baa8294e71fc2fba0a4f54f488b5eTimo Sirainen#include "login-proxy.h"
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen#include "ssl-proxy.h"
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen#include "client-common.h"
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen#include <stdlib.h>
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenstruct client *clients = NULL, *last_client = NULL;
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainenstatic unsigned int clients_count = 0;
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainenstatic void client_idle_disconnect_timeout(struct client *client)
9fd2181788a61500641c66aec0f8c746b19bf830Timo Sirainen{
9fd2181788a61500641c66aec0f8c746b19bf830Timo Sirainen const char *user_reason, *destroy_reason;
9fd2181788a61500641c66aec0f8c746b19bf830Timo Sirainen unsigned int secs;
9fd2181788a61500641c66aec0f8c746b19bf830Timo Sirainen
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen if (client->master_tag != 0) {
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainen secs = ioloop_time - client->auth_finished;
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainen user_reason = "Timeout while finishing login.";
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen destroy_reason = t_strdup_printf(
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen "Timeout while finishing login (waited %u secs)", secs);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen client_log_err(client, destroy_reason);
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen } else if (client->auth_request != NULL) {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen user_reason =
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen "Disconnected for inactivity during authentication.";
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen destroy_reason =
a8d47e2427558d5011dfc75694b704760c1ef8baTimo Sirainen "Disconnected: Inactivity during authentication";
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen } else if (client->login_proxy != NULL) {
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen secs = ioloop_time - client->created;
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen user_reason = "Timeout while finishing login.";
4c892b0d94c5b1d6853dbe8e0b38059ea5b08ecaTimo Sirainen destroy_reason = t_strdup_printf(
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen "proxy: Logging in to %s:%u timed out "
abc79eec93e58e0152cd1d483f37be66c26811b9Timo Sirainen "(state=%u, duration=%us)",
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen login_proxy_get_host(client->login_proxy),
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen login_proxy_get_port(client->login_proxy),
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen client->proxy_state, secs);
4c892b0d94c5b1d6853dbe8e0b38059ea5b08ecaTimo Sirainen client_log_err(client, destroy_reason);
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen } else {
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen user_reason = "Disconnected for inactivity.";
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen destroy_reason = "Disconnected: Inactivity";
013a8a91c83c6ea24bc75322b81235f19e26fa8fTimo Sirainen }
d9076f5939edf5d20a261494b1a861dcbb0d32e2Timo Sirainen client_notify_disconnect(client, CLIENT_DISCONNECT_TIMEOUT, user_reason);
a8d47e2427558d5011dfc75694b704760c1ef8baTimo Sirainen client_destroy(client, destroy_reason);
a8d47e2427558d5011dfc75694b704760c1ef8baTimo Sirainen}
a8d47e2427558d5011dfc75694b704760c1ef8baTimo Sirainen
a8d47e2427558d5011dfc75694b704760c1ef8baTimo Sirainenstatic void client_open_streams(struct client *client)
a8d47e2427558d5011dfc75694b704760c1ef8baTimo Sirainen{
a8d47e2427558d5011dfc75694b704760c1ef8baTimo Sirainen client->input =
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen i_stream_create_fd(client->fd, LOGIN_MAX_INBUF_SIZE, FALSE);
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen client->output =
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen o_stream_create_fd(client->fd, LOGIN_MAX_OUTBUF_SIZE, FALSE);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen o_stream_set_no_error_handling(client->output, TRUE);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen if (login_rawlog_dir != NULL) {
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen if (iostream_rawlog_create(login_rawlog_dir, &client->input,
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen &client->output) < 0)
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen login_rawlog_dir = NULL;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen }
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen}
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainenstatic bool client_is_trusted(struct client *client)
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen{
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen const char *const *net;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen struct ip_addr net_ip;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen unsigned int bits;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen if (client->set->login_trusted_networks == NULL)
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen return FALSE;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen net = t_strsplit_spaces(client->set->login_trusted_networks, ", ");
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen for (; *net != NULL; net++) {
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen if (net_parse_range(*net, &net_ip, &bits) < 0) {
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen i_error("login_trusted_networks: "
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen "Invalid network '%s'", *net);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen break;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen }
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen if (net_is_in_network(&client->ip, &net_ip, bits))
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen return TRUE;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen }
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen return FALSE;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen}
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenstruct client *
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenclient_create(int fd, bool ssl, pool_t pool,
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen const struct login_settings *set,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen const struct master_service_ssl_settings *ssl_set,
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen void **other_sets,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen const struct ip_addr *local_ip, const struct ip_addr *remote_ip)
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen{
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen struct client *client;
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen i_assert(fd != -1);
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen client = login_binary->client_vfuncs->alloc(pool);
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen client->v = *login_binary->client_vfuncs;
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen if (client->v.auth_send_challenge == NULL)
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen client->v.auth_send_challenge = client_auth_send_challenge;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (client->v.auth_parse_response == NULL)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen client->v.auth_parse_response = client_auth_parse_response;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen client->created = ioloop_time;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen client->refcount = 1;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen client->pool = pool;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen client->set = set;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen client->ssl_set = ssl_set;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen client->real_local_ip = client->local_ip = *local_ip;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen client->real_remote_ip = client->ip = *remote_ip;
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen client->fd = fd;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen client->tls = ssl;
5666a3d6a7ea89362b8d9e8b39b15424cd9d6388Timo Sirainen client->trusted = client_is_trusted(client);
a26b7e87b4157cfa800f9bcd8c4c044462d21268Timo Sirainen client->secured = ssl || client->trusted ||
a26b7e87b4157cfa800f9bcd8c4c044462d21268Timo Sirainen net_ip_compare(remote_ip, local_ip);
a26b7e87b4157cfa800f9bcd8c4c044462d21268Timo Sirainen client->proxy_ttl = LOGIN_PROXY_TTL;
a26b7e87b4157cfa800f9bcd8c4c044462d21268Timo Sirainen
a26b7e87b4157cfa800f9bcd8c4c044462d21268Timo Sirainen if (last_client == NULL)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen last_client = client;
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen DLLIST_PREPEND(&clients, client);
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen clients_count++;
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen client->to_disconnect =
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen timeout_add(CLIENT_LOGIN_TIMEOUT_MSECS,
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen client_idle_disconnect_timeout, client);
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen client_open_streams(client);
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen client->v.create(client, other_sets);
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen if (auth_client_is_connected(auth_client))
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen client_notify_auth_ready(client);
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen else
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen client_set_auth_waiting(client);
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen login_refresh_proctitle();
e51cfb5506de764499cb5b81a098b23cf46f90f1Timo Sirainen return client;
e51cfb5506de764499cb5b81a098b23cf46f90f1Timo Sirainen}
e51cfb5506de764499cb5b81a098b23cf46f90f1Timo Sirainen
e51cfb5506de764499cb5b81a098b23cf46f90f1Timo Sirainenvoid client_destroy(struct client *client, const char *reason)
e51cfb5506de764499cb5b81a098b23cf46f90f1Timo Sirainen{
e51cfb5506de764499cb5b81a098b23cf46f90f1Timo Sirainen if (client->destroyed)
e51cfb5506de764499cb5b81a098b23cf46f90f1Timo Sirainen return;
e51cfb5506de764499cb5b81a098b23cf46f90f1Timo Sirainen client->destroyed = TRUE;
e51cfb5506de764499cb5b81a098b23cf46f90f1Timo Sirainen
e51cfb5506de764499cb5b81a098b23cf46f90f1Timo Sirainen if (!client->login_success && reason != NULL) {
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen reason = t_strconcat(reason, " ",
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen client_get_extra_disconnect_reason(client), NULL);
a443e5aaf632257bfd1e7aa9b3c42c09512bbe43Timo Sirainen }
a443e5aaf632257bfd1e7aa9b3c42c09512bbe43Timo Sirainen if (reason != NULL)
a443e5aaf632257bfd1e7aa9b3c42c09512bbe43Timo Sirainen client_log(client, reason);
a443e5aaf632257bfd1e7aa9b3c42c09512bbe43Timo Sirainen
a443e5aaf632257bfd1e7aa9b3c42c09512bbe43Timo Sirainen if (last_client == client)
a443e5aaf632257bfd1e7aa9b3c42c09512bbe43Timo Sirainen last_client = client->prev;
a443e5aaf632257bfd1e7aa9b3c42c09512bbe43Timo Sirainen DLLIST_REMOVE(&clients, client);
a443e5aaf632257bfd1e7aa9b3c42c09512bbe43Timo Sirainen
a443e5aaf632257bfd1e7aa9b3c42c09512bbe43Timo Sirainen if (client->input != NULL)
a443e5aaf632257bfd1e7aa9b3c42c09512bbe43Timo Sirainen i_stream_close(client->input);
a443e5aaf632257bfd1e7aa9b3c42c09512bbe43Timo Sirainen if (client->output != NULL)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen o_stream_close(client->output);
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (client->master_tag != 0) {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen i_assert(client->auth_request == NULL);
013a8a91c83c6ea24bc75322b81235f19e26fa8fTimo Sirainen i_assert(client->authenticating);
013a8a91c83c6ea24bc75322b81235f19e26fa8fTimo Sirainen i_assert(client->refcount > 1);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen client->authenticating = FALSE;
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen master_auth_request_abort(master_auth, client->master_tag);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen client->refcount--;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen } else if (client->auth_request != NULL) {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen i_assert(client->authenticating);
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen sasl_server_auth_abort(client);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen } else {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen i_assert(!client->authenticating);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen }
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (client->io != NULL)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen io_remove(&client->io);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (client->to_disconnect != NULL)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen timeout_remove(&client->to_disconnect);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (client->to_auth_waiting != NULL)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen timeout_remove(&client->to_auth_waiting);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (client->auth_response != NULL)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen str_free(&client->auth_response);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (client->fd != -1) {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen net_disconnect(client->fd);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen client->fd = -1;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen }
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a2150da2dc906c26a26219cbefbe28a119aafee2Timo Sirainen if (client->proxy_password != NULL) {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen safe_memset(client->proxy_password, 0,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen strlen(client->proxy_password));
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen i_free_and_null(client->proxy_password);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen }
f9142439f2b5e86065af7420e80fe52835227dc8Timo Sirainen
f9142439f2b5e86065af7420e80fe52835227dc8Timo Sirainen if (client->proxy_sasl_client != NULL)
f9142439f2b5e86065af7420e80fe52835227dc8Timo Sirainen dsasl_client_free(&client->proxy_sasl_client);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (client->login_proxy != NULL)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen login_proxy_free(&client->login_proxy);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (client->v.destroy != NULL)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen client->v.destroy(client);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (client_unref(&client) && initial_service_count == 1) {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen /* as soon as this connection is done with proxying
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen (or whatever), the process will die. there's no need for
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen authentication anymore, so close the connection.
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen do this only with initial service_count=1, in case there
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen are other clients with pending authentications */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen auth_client_disconnect(auth_client, "unnecessary connection");
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen }
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen login_client_destroyed();
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen login_refresh_proctitle();
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen}
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenvoid client_destroy_success(struct client *client, const char *reason)
88b0427d90f1d3c2c5fb3171e53a505c46e2c39dTimo Sirainen{
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen client->login_success = TRUE;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen client_destroy(client, reason);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen}
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenvoid client_destroy_internal_failure(struct client *client)
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen{
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen client_notify_disconnect(client, CLIENT_DISCONNECT_INTERNAL_ERROR,
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen "Internal login failure. "
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen "Refer to server log for more information.");
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen client_destroy(client, t_strdup_printf(
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainen "Internal login failure (pid=%s id=%u)",
94ce7e7700cda14a8342cb08e7285507b4b531daTimo Sirainen my_pid, client->master_auth_id));
94ce7e7700cda14a8342cb08e7285507b4b531daTimo Sirainen}
4654f788834c9d7920a351306b89cf5d1c21772eTimo Sirainen
94ce7e7700cda14a8342cb08e7285507b4b531daTimo Sirainenvoid client_ref(struct client *client)
4654f788834c9d7920a351306b89cf5d1c21772eTimo Sirainen{
4654f788834c9d7920a351306b89cf5d1c21772eTimo Sirainen client->refcount++;
4654f788834c9d7920a351306b89cf5d1c21772eTimo Sirainen}
4654f788834c9d7920a351306b89cf5d1c21772eTimo Sirainen
4654f788834c9d7920a351306b89cf5d1c21772eTimo Sirainenbool client_unref(struct client **_client)
4654f788834c9d7920a351306b89cf5d1c21772eTimo Sirainen{
4654f788834c9d7920a351306b89cf5d1c21772eTimo Sirainen struct client *client = *_client;
4654f788834c9d7920a351306b89cf5d1c21772eTimo Sirainen
4654f788834c9d7920a351306b89cf5d1c21772eTimo Sirainen i_assert(client->refcount > 0);
4654f788834c9d7920a351306b89cf5d1c21772eTimo Sirainen if (--client->refcount > 0)
4654f788834c9d7920a351306b89cf5d1c21772eTimo Sirainen return TRUE;
4654f788834c9d7920a351306b89cf5d1c21772eTimo Sirainen
94ce7e7700cda14a8342cb08e7285507b4b531daTimo Sirainen *_client = NULL;
4654f788834c9d7920a351306b89cf5d1c21772eTimo Sirainen
4654f788834c9d7920a351306b89cf5d1c21772eTimo Sirainen i_assert(client->destroyed);
3398d5e2b883812de5d569721c8294b581e1d9e6Timo Sirainen i_assert(client->login_proxy == NULL);
3398d5e2b883812de5d569721c8294b581e1d9e6Timo Sirainen
3398d5e2b883812de5d569721c8294b581e1d9e6Timo Sirainen if (client->ssl_proxy != NULL)
3398d5e2b883812de5d569721c8294b581e1d9e6Timo Sirainen ssl_proxy_free(&client->ssl_proxy);
b06633c63fde22b6c8837ae70b2f95fe60075b0aTimo Sirainen if (client->input != NULL)
b06633c63fde22b6c8837ae70b2f95fe60075b0aTimo Sirainen i_stream_unref(&client->input);
b06633c63fde22b6c8837ae70b2f95fe60075b0aTimo Sirainen if (client->output != NULL)
3398d5e2b883812de5d569721c8294b581e1d9e6Timo Sirainen o_stream_unref(&client->output);
3398d5e2b883812de5d569721c8294b581e1d9e6Timo Sirainen
3398d5e2b883812de5d569721c8294b581e1d9e6Timo Sirainen i_free(client->proxy_user);
3398d5e2b883812de5d569721c8294b581e1d9e6Timo Sirainen i_free(client->proxy_master_user);
b06633c63fde22b6c8837ae70b2f95fe60075b0aTimo Sirainen i_free(client->virtual_user);
b06633c63fde22b6c8837ae70b2f95fe60075b0aTimo Sirainen i_free(client->virtual_user_orig);
3398d5e2b883812de5d569721c8294b581e1d9e6Timo Sirainen i_free(client->auth_mech_name);
3398d5e2b883812de5d569721c8294b581e1d9e6Timo Sirainen i_free(client->master_data_prefix);
3398d5e2b883812de5d569721c8294b581e1d9e6Timo Sirainen pool_unref(&client->pool);
3398d5e2b883812de5d569721c8294b581e1d9e6Timo Sirainen
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainen i_assert(clients_count > 0);
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainen clients_count--;
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainen
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainen master_service_client_connection_destroyed(master_service);
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainen login_refresh_proctitle();
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainen return FALSE;
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen}
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainenvoid client_destroy_oldest(void)
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen{
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen struct client *client;
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen if (last_client == NULL) {
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen /* we have no clients */
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen return;
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen }
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
5736aef6d0abe6796e57c2eda68f5c25db677918Timo Sirainen /* destroy the last client that hasn't successfully authenticated yet.
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen this is usually the last client, but don't kill it if it's just
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen waiting for master to finish its job. */
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen for (client = last_client; client != NULL; client = client->prev) {
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen if (client->master_tag == 0)
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen break;
5e751dbaecf7c337abc149f328c4a13ee5c15134Timo Sirainen }
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (client == NULL)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen client = last_client;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen client_notify_disconnect(client, CLIENT_DISCONNECT_RESOURCE_CONSTRAINT,
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen "Connection queue full");
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen client_destroy(client, "Disconnected: Connection queue full");
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen}
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainenvoid clients_destroy_all_reason(const char *reason)
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen{
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen struct client *client, *next;
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen for (client = clients; client != NULL; client = next) {
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen next = client->next;
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen client_notify_disconnect(client,
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen CLIENT_DISCONNECT_SYSTEM_SHUTDOWN, reason);
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen client_destroy(client, reason);
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen }
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen}
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen
117a55d4260651770705ecb96f68be2dab03b99bTimo Sirainenvoid clients_destroy_all(void)
117a55d4260651770705ecb96f68be2dab03b99bTimo Sirainen{
117a55d4260651770705ecb96f68be2dab03b99bTimo Sirainen clients_destroy_all_reason("Disconnected: Shutting down");
117a55d4260651770705ecb96f68be2dab03b99bTimo Sirainen}
117a55d4260651770705ecb96f68be2dab03b99bTimo Sirainen
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainenstatic void client_start_tls(struct client *client)
117a55d4260651770705ecb96f68be2dab03b99bTimo Sirainen{
117a55d4260651770705ecb96f68be2dab03b99bTimo Sirainen int fd_ssl;
117a55d4260651770705ecb96f68be2dab03b99bTimo Sirainen
117a55d4260651770705ecb96f68be2dab03b99bTimo Sirainen client_ref(client);
117a55d4260651770705ecb96f68be2dab03b99bTimo Sirainen if (!client_unref(&client) || client->destroyed)
117a55d4260651770705ecb96f68be2dab03b99bTimo Sirainen return;
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen fd_ssl = ssl_proxy_alloc(client->fd, &client->ip, client->pool,
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen client->set, client->ssl_set,
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen &client->ssl_proxy);
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen if (fd_ssl == -1) {
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen client_notify_disconnect(client,
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen CLIENT_DISCONNECT_INTERNAL_ERROR,
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen "TLS initialization failed.");
dd7cbb32412c2f4d2d223af66672535bc1237246Timo Sirainen client_destroy(client,
dd7cbb32412c2f4d2d223af66672535bc1237246Timo Sirainen "Disconnected: TLS initialization failed.");
dd7cbb32412c2f4d2d223af66672535bc1237246Timo Sirainen return;
dd7cbb32412c2f4d2d223af66672535bc1237246Timo Sirainen }
dd7cbb32412c2f4d2d223af66672535bc1237246Timo Sirainen ssl_proxy_set_client(client->ssl_proxy, client);
dd7cbb32412c2f4d2d223af66672535bc1237246Timo Sirainen ssl_proxy_start(client->ssl_proxy);
dd7cbb32412c2f4d2d223af66672535bc1237246Timo Sirainen
dd7cbb32412c2f4d2d223af66672535bc1237246Timo Sirainen client->starttls = TRUE;
dd7cbb32412c2f4d2d223af66672535bc1237246Timo Sirainen client->tls = TRUE;
dd7cbb32412c2f4d2d223af66672535bc1237246Timo Sirainen client->secured = TRUE;
dd7cbb32412c2f4d2d223af66672535bc1237246Timo Sirainen login_refresh_proctitle();
dd7cbb32412c2f4d2d223af66672535bc1237246Timo Sirainen
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen client->fd = fd_ssl;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen client->io = io_add(client->fd, IO_READ, client_input, client);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_stream_unref(&client->input);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen o_stream_unref(&client->output);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen client_open_streams(client);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen client->v.starttls(client);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen}
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic int client_output_starttls(struct client *client)
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen int ret;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen if ((ret = o_stream_flush(client->output)) < 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen client_destroy(client, "Disconnected");
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return 1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen if (ret > 0) {
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen o_stream_unset_flush_callback(client->output);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen client_start_tls(client);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen }
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainen return 1;
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainen}
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainenvoid client_cmd_starttls(struct client *client)
08a33e7c0cf5ab2c4a0c96a55056cc3251d14c5eTimo Sirainen{
cb17980a661554ebb3fd099c77e92a5be4d304ecTimo Sirainen if (client->tls) {
cb17980a661554ebb3fd099c77e92a5be4d304ecTimo Sirainen client->v.notify_starttls(client, FALSE, "TLS is already active.");
cb17980a661554ebb3fd099c77e92a5be4d304ecTimo Sirainen return;
cb17980a661554ebb3fd099c77e92a5be4d304ecTimo Sirainen }
d2d5871fa9e7226df694ff7a4be511167b35b305Timo Sirainen
d2c853636ec2d99c9f96da877ff520a3b86a18baTimo Sirainen if (!client_is_tls_enabled(client)) {
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainen client->v.notify_starttls(client, FALSE, "TLS support isn't enabled.");
57f5683fd9dc9bc79816c418bb30fdbc33b68a8cTimo Sirainen return;
57f5683fd9dc9bc79816c418bb30fdbc33b68a8cTimo Sirainen }
57f5683fd9dc9bc79816c418bb30fdbc33b68a8cTimo Sirainen
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainen /* remove input handler, SSL proxy gives us a new fd. we also have to
57f5683fd9dc9bc79816c418bb30fdbc33b68a8cTimo Sirainen remove it in case we have to wait for buffer to be flushed */
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainen if (client->io != NULL)
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainen io_remove(&client->io);
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen
55a14bce15b9f44441b5f56616d73651a294d770Timo Sirainen client->v.notify_starttls(client, TRUE, "Begin TLS negotiation now.");
55a14bce15b9f44441b5f56616d73651a294d770Timo Sirainen
b16ee3cbbcd18cb86f2f73b5cc163ebfb995ffafTimo Sirainen /* uncork the old fd */
55a14bce15b9f44441b5f56616d73651a294d770Timo Sirainen o_stream_uncork(client->output);
55a14bce15b9f44441b5f56616d73651a294d770Timo Sirainen
55a14bce15b9f44441b5f56616d73651a294d770Timo Sirainen if (o_stream_flush(client->output) <= 0) {
55a14bce15b9f44441b5f56616d73651a294d770Timo Sirainen /* the buffer has to be flushed */
b16ee3cbbcd18cb86f2f73b5cc163ebfb995ffafTimo Sirainen o_stream_set_flush_pending(client->output, TRUE);
b16ee3cbbcd18cb86f2f73b5cc163ebfb995ffafTimo Sirainen o_stream_set_flush_callback(client->output,
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen client_output_starttls, client);
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen } else {
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen client_start_tls(client);
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen }
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen}
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainenunsigned int clients_get_count(void)
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainen{
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainen return clients_count;
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainen}
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainen
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainenconst char *client_get_session_id(struct client *client)
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainen{
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainen buffer_t *buf, *base64_buf;
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainen struct timeval tv;
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainen uint64_t timestamp;
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainen unsigned int i;
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainen
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainen if (client->session_id != NULL)
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainen return client->session_id;
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainen
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainen buf = buffer_create_dynamic(pool_datastack_create(), 24);
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainen base64_buf = buffer_create_dynamic(pool_datastack_create(), 24*2);
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainen
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainen if (gettimeofday(&tv, NULL) < 0)
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainen i_fatal("gettimeofday(): %m");
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainen timestamp = tv.tv_usec + (long long)tv.tv_sec * 1000ULL*1000ULL;
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainen
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainen /* add lowest 48 bits of the timestamp. this gives us a bit less than
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainen 9 years until it wraps */
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainen for (i = 0; i < 48; i += 8)
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainen buffer_append_c(buf, (timestamp >> i) & 0xff);
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainen
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainen buffer_append_c(buf, client->remote_port & 0xff);
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainen buffer_append_c(buf, (client->remote_port >> 16) & 0xff);
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainen#ifdef HAVE_IPV6
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainen if (IPADDR_IS_V6(&client->ip))
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainen buffer_append(buf, &client->ip.u.ip6, sizeof(client->ip.u.ip6));
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainen else
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen#endif
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen buffer_append(buf, &client->ip.u.ip4, sizeof(client->ip.u.ip4));
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen base64_encode(buf->data, buf->used, base64_buf);
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen client->session_id = p_strdup(client->pool, str_c(base64_buf));
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen return client->session_id;
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen}
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainenstatic struct var_expand_table login_var_expand_empty_tab[] = {
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen { 'u', NULL, "user" },
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen { 'n', NULL, "username" },
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen { 'd', NULL, "domain" },
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen { 's', NULL, "service" },
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen { 'h', NULL, "home" },
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen { 'l', NULL, "lip" },
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen { 'r', NULL, "rip" },
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen { 'p', NULL, "pid" },
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen { 'm', NULL, "mech" },
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen { 'a', NULL, "lport" },
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen { 'b', NULL, "rport" },
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen { 'c', NULL, "secured" },
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen { 'k', NULL, "ssl_security" },
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen { 'e', NULL, "mail_pid" },
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen { '\0', NULL, "session" },
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen { '\0', NULL, "real_lip" },
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen { '\0', NULL, "real_rip" },
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen { '\0', NULL, "real_lport" },
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen { '\0', NULL, "real_rport" },
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen { '\0', NULL, "orig_user" },
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen { '\0', NULL, "orig_username" },
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen { '\0', NULL, "orig_domain" },
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen { '\0', NULL, NULL }
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen};
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainenstatic const struct var_expand_table *
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainenget_var_expand_table(struct client *client)
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen{
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen struct var_expand_table *tab;
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen unsigned int i;
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen tab = t_malloc(sizeof(login_var_expand_empty_tab));
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen memcpy(tab, login_var_expand_empty_tab,
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen sizeof(login_var_expand_empty_tab));
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen if (client->virtual_user != NULL) {
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen tab[0].value = client->virtual_user;
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen tab[1].value = t_strcut(client->virtual_user, '@');
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen tab[2].value = strchr(client->virtual_user, '@');
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen if (tab[2].value != NULL) tab[2].value++;
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen for (i = 0; i < 3; i++)
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen tab[i].value = str_sanitize(tab[i].value, 80);
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen }
tab[3].value = login_binary->protocol;
tab[4].value = getenv("HOME");
tab[5].value = net_ip2addr(&client->local_ip);
tab[6].value = net_ip2addr(&client->ip);
tab[7].value = my_pid;
tab[8].value = client->auth_mech_name == NULL ? NULL :
str_sanitize(client->auth_mech_name, MAX_MECH_NAME);
tab[9].value = dec2str(client->local_port);
tab[10].value = dec2str(client->remote_port);
if (!client->tls) {
tab[11].value = client->secured ? "secured" : NULL;
tab[12].value = "";
} else {
const char *ssl_state =
ssl_proxy_is_handshaked(client->ssl_proxy) ?
"TLS" : "TLS handshaking";
const char *ssl_error =
ssl_proxy_get_last_error(client->ssl_proxy);
tab[11].value = ssl_error == NULL ? ssl_state :
t_strdup_printf("%s: %s", ssl_state, ssl_error);
tab[12].value =
ssl_proxy_get_security_string(client->ssl_proxy);
}
tab[13].value = client->mail_pid == 0 ? "" :
dec2str(client->mail_pid);
tab[14].value = client_get_session_id(client);
tab[15].value = net_ip2addr(&client->real_local_ip);
tab[16].value = net_ip2addr(&client->real_remote_ip);
tab[17].value = dec2str(client->real_local_port);
tab[18].value = dec2str(client->real_remote_port);
if (client->virtual_user_orig == NULL) {
tab[19].value = tab[0].value;
tab[20].value = tab[1].value;
tab[21].value = tab[2].value;
} else {
tab[19].value = client->virtual_user_orig;
tab[20].value = t_strcut(client->virtual_user_orig, '@');
tab[21].value = strchr(client->virtual_user_orig, '@');
if (tab[21].value != NULL) tab[21].value++;
for (i = 0; i < 3; i++)
tab[i].value = str_sanitize(tab[i].value, 80);
}
return tab;
}
static bool have_username_key(const char *str)
{
char key;
for (; *str != '\0'; str++) {
if (str[0] == '%' && str[1] != '\0') {
str++;
key = var_get_key(str);
if (key == 'u' || key == 'n')
return TRUE;
}
}
return FALSE;
}
static const char *
client_get_log_str(struct client *client, const char *msg)
{
static struct var_expand_table static_tab[3] = {
{ 's', NULL, NULL },
{ '$', NULL, NULL },
{ '\0', NULL, NULL }
};
const struct var_expand_table *var_expand_table;
struct var_expand_table *tab;
char *const *e;
string_t *str, *str2;
unsigned int pos;
var_expand_table = get_var_expand_table(client);
tab = t_malloc(sizeof(static_tab));
memcpy(tab, static_tab, sizeof(static_tab));
str = t_str_new(256);
str2 = t_str_new(128);
for (e = client->set->log_format_elements_split; *e != NULL; e++) {
pos = str_len(str);
var_expand(str, *e, var_expand_table);
if (have_username_key(*e)) {
/* username is added even if it's empty */
} else {
str_truncate(str2, 0);
var_expand(str2, *e, login_var_expand_empty_tab);
if (strcmp(str_c(str)+pos, str_c(str2)) == 0) {
/* empty %variables, don't add */
str_truncate(str, pos);
continue;
}
}
if (str_len(str) > 0)
str_append(str, ", ");
}
if (str_len(str) > 0)
str_truncate(str, str_len(str)-2);
tab[0].value = t_strdup(str_c(str));
tab[1].value = msg;
str_truncate(str, 0);
var_expand(str, client->set->login_log_format, tab);
return str_c(str);
}
void client_log(struct client *client, const char *msg)
{
T_BEGIN {
i_info("%s", client_get_log_str(client, msg));
} T_END;
}
void client_log_err(struct client *client, const char *msg)
{
T_BEGIN {
i_error("%s", client_get_log_str(client, msg));
} T_END;
}
void client_log_warn(struct client *client, const char *msg)
{
T_BEGIN {
i_warning("%s", client_get_log_str(client, msg));
} T_END;
}
bool client_is_tls_enabled(struct client *client)
{
return ssl_initialized && strcmp(client->ssl_set->ssl, "no") != 0;
}
const char *client_get_extra_disconnect_reason(struct client *client)
{
unsigned int auth_secs = client->auth_first_started == 0 ? 0 :
ioloop_time - client->auth_first_started;
if (client->set->auth_ssl_require_client_cert &&
client->ssl_proxy != NULL) {
if (ssl_proxy_has_broken_client_cert(client->ssl_proxy))
return "(client sent an invalid cert)";
if (!ssl_proxy_has_valid_client_cert(client->ssl_proxy))
return "(client didn't send a cert)";
}
if (!client->notified_auth_ready)
return t_strdup_printf(
"(disconnected before auth was ready, waited %u secs)",
(unsigned int)(ioloop_time - client->created));
if (client->auth_attempts == 0) {
return t_strdup_printf("(no auth attempts in %u secs)",
(unsigned int)(ioloop_time - client->created));
}
/* some auth attempts without SSL/TLS */
if (client->auth_tried_disabled_plaintext)
return "(tried to use disallowed plaintext auth)";
if (client->set->auth_ssl_require_client_cert &&
client->ssl_proxy == NULL)
return "(cert required, client didn't start TLS)";
if (client->auth_tried_unsupported_mech)
return "(tried to use unsupported auth mechanism)";
if (client->auth_waiting && client->auth_attempts == 1) {
return t_strdup_printf("(client didn't finish SASL auth, "
"waited %u secs)", auth_secs);
}
if (client->auth_request != NULL && client->auth_attempts == 1) {
return t_strdup_printf("(disconnected while authenticating, "
"waited %u secs)", auth_secs);
}
if (client->authenticating && client->auth_attempts == 1) {
return t_strdup_printf("(disconnected while finishing login, "
"waited %u secs)", auth_secs);
}
if (client->auth_try_aborted && client->auth_attempts == 1)
return "(aborted authentication)";
if (client->auth_process_comm_fail)
return "(auth process communication failure)";
if (client->proxy_auth_failed)
return "(proxy dest auth failed)";
if (client->auth_successes > 0) {
return t_strdup_printf("(internal failure, %u successful auths)",
client->auth_successes);
}
if (client->auth_user_disabled)
return "(user disabled)";
if (client->auth_pass_expired)
return "(password expired)";
return t_strdup_printf("(auth failed, %u attempts in %u secs)",
client->auth_attempts, auth_secs);
}
void client_notify_disconnect(struct client *client,
enum client_disconnect_reason reason,
const char *text)
{
if (!client->notified_disconnect) {
if (client->v.notify_disconnect != NULL)
client->v.notify_disconnect(client, reason, text);
client->notified_disconnect = TRUE;
}
}
void client_notify_auth_ready(struct client *client)
{
if (!client->notified_auth_ready) {
if (client->v.notify_auth_ready != NULL)
client->v.notify_auth_ready(client);
client->notified_auth_ready = TRUE;
}
}
void client_notify_status(struct client *client, bool bad, const char *text)
{
if (client->v.notify_status != NULL)
client->v.notify_status(client, bad, text);
}
void client_send_raw_data(struct client *client, const void *data, size_t size)
{
ssize_t ret;
ret = o_stream_send(client->output, data, size);
if (ret < 0 || (size_t)ret != size) {
/* either disconnection or buffer full. in either case we want
this connection destroyed. however destroying it here might
break things if client is still tried to be accessed without
being referenced.. */
i_stream_close(client->input);
}
}
void client_send_raw(struct client *client, const char *data)
{
client_send_raw_data(client, data, strlen(data));
}
bool client_read(struct client *client)
{
switch (i_stream_read(client->input)) {
case -2:
/* buffer full */
client_notify_disconnect(client,
CLIENT_DISCONNECT_RESOURCE_CONSTRAINT,
"Input buffer full, aborting");
client_destroy(client, "Disconnected: Input buffer full");
return FALSE;
case -1:
/* disconnected */
client_destroy(client, "Disconnected");
return FALSE;
case 0:
/* nothing new read */
return TRUE;
default:
/* something was read */
return TRUE;
}
}
void client_input(struct client *client)
{
client->v.input(client);
}