bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
1d4f710106fb498750456724628da6063e012e6dTimo Sirainen
46552a931924c2d743f045e95b08c3ce6beda91aTimo Sirainen#include "login-common.h"
9132f9df4e12ed5293c70957813aa3736444a13cTimo Sirainen#include "array.h"
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen#include "hostpid.h"
d3d769026fae5d21c2d29614d3bc4579e8d79e81Timo Sirainen#include "llist.h"
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#include "istream.h"
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#include "ostream.h"
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen#include "iostream-ssl.h"
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen#include "iostream-proxy.h"
baebb412a9a5a44b1756e01cfa3b99f5d8a846b6Timo Sirainen#include "iostream-rawlog.h"
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#include "process-title.h"
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen#include "hook-build.h"
b55f914c0ade77252cfd798ea8eb9a84bda56315Timo Sirainen#include "buffer.h"
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen#include "str.h"
c4ec7cb598805b1387dc3aab59ec8f32d8cc24e1Timo Sirainen#include "strescape.h"
b55f914c0ade77252cfd798ea8eb9a84bda56315Timo Sirainen#include "base64.h"
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen#include "str-sanitize.h"
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#include "safe-memset.h"
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen#include "var-expand.h"
92c49f3005f4dff1a6f576fffa8112ef6d1cae7fTimo Sirainen#include "master-interface.h"
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#include "master-service.h"
1d2c463d23f09f15727edae9c78b07ec6a7a27daTimo Sirainen#include "master-service-ssl-settings.h"
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#include "master-auth.h"
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#include "auth-client.h"
de754cb78f75e8b3b994cddafe41c9ed1467c33dTimo Sirainen#include "dsasl-client.h"
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#include "login-proxy.h"
1d4f710106fb498750456724628da6063e012e6dTimo Sirainen#include "client-common.h"
1d4f710106fb498750456724628da6063e012e6dTimo Sirainen
0b3e92b6043435c5aa9f1cf1d04b632f3e19abd9Phil Carmodystruct client *clients = NULL;
0b3e92b6043435c5aa9f1cf1d04b632f3e19abd9Phil Carmodystatic struct client *last_client = NULL;
ab0d9eecd85f74acae18fe88529302e0776cc500Timo Sirainenstatic unsigned int clients_count = 0;
ad004e44be109684521494b5af2ad1da39b8bb27Timo Sirainen
a7efba62b6235e5efc124cbf702ddeb547ca3665Timo Sirainenstatic struct client *client_fd_proxies = NULL;
0256180043b9f55b606b523b775e8b23b1b12f83Timo Sirainenstatic unsigned int client_fd_proxies_count = 0;
a7efba62b6235e5efc124cbf702ddeb547ca3665Timo Sirainen
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainenstruct login_client_module_hooks {
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen struct module *module;
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen const struct login_client_hooks *hooks;
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen};
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainenstatic ARRAY(struct login_client_module_hooks) module_hooks = ARRAY_INIT;
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainenvoid login_client_hooks_add(struct module *module,
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen const struct login_client_hooks *hooks)
9132f9df4e12ed5293c70957813aa3736444a13cTimo Sirainen{
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen struct login_client_module_hooks *hook;
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen hook = array_append_space(&module_hooks);
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen hook->module = module;
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen hook->hooks = hooks;
9132f9df4e12ed5293c70957813aa3736444a13cTimo Sirainen}
9132f9df4e12ed5293c70957813aa3736444a13cTimo Sirainen
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainenvoid login_client_hooks_remove(const struct login_client_hooks *hooks)
9132f9df4e12ed5293c70957813aa3736444a13cTimo Sirainen{
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen const struct login_client_module_hooks *module_hook;
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen unsigned int idx = UINT_MAX;
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen array_foreach(&module_hooks, module_hook) {
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen if (module_hook->hooks == hooks) {
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen idx = array_foreach_idx(&module_hooks, module_hook);
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen break;
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen }
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen }
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen i_assert(idx != UINT_MAX);
9132f9df4e12ed5293c70957813aa3736444a13cTimo Sirainen
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen array_delete(&module_hooks, idx, 1);
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen}
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainenstatic void hook_login_client_allocated(struct client *client)
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen{
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen const struct login_client_module_hooks *module_hook;
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen struct hook_build_context *ctx;
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen ctx = hook_build_init((void *)&client->v, sizeof(client->v));
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen client->vlast = &client->v;
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen array_foreach(&module_hooks, module_hook) {
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen if (module_hook->hooks->client_allocated != NULL) T_BEGIN {
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen module_hook->hooks->client_allocated(client);
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen hook_build_update(ctx, client->vlast);
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen } T_END;
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen }
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen client->vlast = NULL;
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen hook_build_deinit(&ctx);
9132f9df4e12ed5293c70957813aa3736444a13cTimo Sirainen}
9132f9df4e12ed5293c70957813aa3736444a13cTimo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic void client_idle_disconnect_timeout(struct client *client)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen const char *user_reason, *destroy_reason;
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen unsigned int secs;
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen if (client->master_tag != 0) {
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen secs = ioloop_time - client->auth_finished;
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen user_reason = "Timeout while finishing login.";
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen destroy_reason = t_strdup_printf(
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen "Timeout while finishing login (waited %u secs)", secs);
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen client_log_err(client, destroy_reason);
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen } else if (client->auth_request != NULL) {
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen user_reason =
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen "Disconnected for inactivity during authentication.";
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen destroy_reason =
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen "Disconnected: Inactivity during authentication";
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen } else if (client->login_proxy != NULL) {
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen secs = ioloop_time - client->created;
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen user_reason = "Timeout while finishing login.";
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen destroy_reason = t_strdup_printf(
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen "proxy: Logging in to %s:%u timed out "
2b96880f2d789d125aff6a95eaa7b51f558a6a1cTimo Sirainen "(state=%s, duration=%us)",
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen login_proxy_get_host(client->login_proxy),
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen login_proxy_get_port(client->login_proxy),
2b96880f2d789d125aff6a95eaa7b51f558a6a1cTimo Sirainen client_proxy_get_state(client), secs);
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen client_log_err(client, destroy_reason);
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen } else {
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen user_reason = "Disconnected for inactivity.";
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen destroy_reason = "Disconnected: Inactivity";
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen }
ed16ab579bd058ec5e2b5d02bb41fdadd9e05b31Timo Sirainen client_notify_disconnect(client, CLIENT_DISCONNECT_TIMEOUT, user_reason);
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen client_destroy(client, destroy_reason);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic void client_open_streams(struct client *client)
ad004e44be109684521494b5af2ad1da39b8bb27Timo Sirainen{
e93184a9055c2530366dfe617e07199603c399ddMartti Rannanjärvi client->input = i_stream_create_fd(client->fd, LOGIN_MAX_INBUF_SIZE);
e93184a9055c2530366dfe617e07199603c399ddMartti Rannanjärvi client->output = o_stream_create_fd(client->fd, LOGIN_MAX_OUTBUF_SIZE);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_set_no_error_handling(client->output, TRUE);
baebb412a9a5a44b1756e01cfa3b99f5d8a846b6Timo Sirainen
baebb412a9a5a44b1756e01cfa3b99f5d8a846b6Timo Sirainen if (login_rawlog_dir != NULL) {
baebb412a9a5a44b1756e01cfa3b99f5d8a846b6Timo Sirainen if (iostream_rawlog_create(login_rawlog_dir, &client->input,
baebb412a9a5a44b1756e01cfa3b99f5d8a846b6Timo Sirainen &client->output) < 0)
baebb412a9a5a44b1756e01cfa3b99f5d8a846b6Timo Sirainen login_rawlog_dir = NULL;
baebb412a9a5a44b1756e01cfa3b99f5d8a846b6Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
12c6ef6f1268ed4d5b63709bb4215c481b4f078cTimo Sirainenstatic bool client_is_trusted(struct client *client)
12c6ef6f1268ed4d5b63709bb4215c481b4f078cTimo Sirainen{
12c6ef6f1268ed4d5b63709bb4215c481b4f078cTimo Sirainen const char *const *net;
12c6ef6f1268ed4d5b63709bb4215c481b4f078cTimo Sirainen struct ip_addr net_ip;
12c6ef6f1268ed4d5b63709bb4215c481b4f078cTimo Sirainen unsigned int bits;
12c6ef6f1268ed4d5b63709bb4215c481b4f078cTimo Sirainen
12c6ef6f1268ed4d5b63709bb4215c481b4f078cTimo Sirainen if (client->set->login_trusted_networks == NULL)
12c6ef6f1268ed4d5b63709bb4215c481b4f078cTimo Sirainen return FALSE;
12c6ef6f1268ed4d5b63709bb4215c481b4f078cTimo Sirainen
12c6ef6f1268ed4d5b63709bb4215c481b4f078cTimo Sirainen net = t_strsplit_spaces(client->set->login_trusted_networks, ", ");
12c6ef6f1268ed4d5b63709bb4215c481b4f078cTimo Sirainen for (; *net != NULL; net++) {
12c6ef6f1268ed4d5b63709bb4215c481b4f078cTimo Sirainen if (net_parse_range(*net, &net_ip, &bits) < 0) {
12c6ef6f1268ed4d5b63709bb4215c481b4f078cTimo Sirainen i_error("login_trusted_networks: "
12c6ef6f1268ed4d5b63709bb4215c481b4f078cTimo Sirainen "Invalid network '%s'", *net);
12c6ef6f1268ed4d5b63709bb4215c481b4f078cTimo Sirainen break;
12c6ef6f1268ed4d5b63709bb4215c481b4f078cTimo Sirainen }
12c6ef6f1268ed4d5b63709bb4215c481b4f078cTimo Sirainen
12c6ef6f1268ed4d5b63709bb4215c481b4f078cTimo Sirainen if (net_is_in_network(&client->ip, &net_ip, bits))
12c6ef6f1268ed4d5b63709bb4215c481b4f078cTimo Sirainen return TRUE;
12c6ef6f1268ed4d5b63709bb4215c481b4f078cTimo Sirainen }
12c6ef6f1268ed4d5b63709bb4215c481b4f078cTimo Sirainen return FALSE;
12c6ef6f1268ed4d5b63709bb4215c481b4f078cTimo Sirainen}
12c6ef6f1268ed4d5b63709bb4215c481b4f078cTimo Sirainen
f059a046515f4b2b15a6c2a10a6f12f6166e39a5Timo Sirainenstruct client *
be6e55ff7c81afdc7ed9b47c6021a4f7827e4407Timo Sirainenclient_alloc(int fd, pool_t pool,
66ea9eaaa2d7531b3be8f633937628c94d907031Timo Sirainen const struct master_service_connection *conn,
66ea9eaaa2d7531b3be8f633937628c94d907031Timo Sirainen const struct login_settings *set,
66ea9eaaa2d7531b3be8f633937628c94d907031Timo Sirainen const struct master_service_ssl_settings *ssl_set)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct client *client;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_assert(fd != -1);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
5a250816ffc4cc5db203f9410ea99b6601c7b91aTimo Sirainen client = login_binary->client_vfuncs->alloc(pool);
5a250816ffc4cc5db203f9410ea99b6601c7b91aTimo Sirainen client->v = *login_binary->client_vfuncs;
46ec792dd4ccf6c34706c4774228301fafde6aa9Timo Sirainen if (client->v.auth_send_challenge == NULL)
46ec792dd4ccf6c34706c4774228301fafde6aa9Timo Sirainen client->v.auth_send_challenge = client_auth_send_challenge;
46ec792dd4ccf6c34706c4774228301fafde6aa9Timo Sirainen if (client->v.auth_parse_response == NULL)
46ec792dd4ccf6c34706c4774228301fafde6aa9Timo Sirainen client->v.auth_parse_response = client_auth_parse_response;
4c6ddf2491104f917d00e6900e833e80ea02c7b6Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->created = ioloop_time;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->refcount = 1;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->pool = pool;
b045b66988bfbaa2795791e42ee724fae6f0db1cAki Tuomi client->preproxy_pool = pool_alloconly_create(MEMPOOL_GROWING"preproxy pool", 256);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->set = set;
f29756821a4c6b12b73e4a2a3e1c230117a43773Timo Sirainen client->ssl_set = ssl_set;
9132f9df4e12ed5293c70957813aa3736444a13cTimo Sirainen p_array_init(&client->module_contexts, client->pool, 5);
a05fec120ecd8c4ed6331c42100cba42adf22893Stephan Bosch
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->fd = fd;
a05fec120ecd8c4ed6331c42100cba42adf22893Stephan Bosch client->local_ip = conn->local_ip;
a05fec120ecd8c4ed6331c42100cba42adf22893Stephan Bosch client->local_port = conn->local_port;
a05fec120ecd8c4ed6331c42100cba42adf22893Stephan Bosch client->ip = conn->remote_ip;
a05fec120ecd8c4ed6331c42100cba42adf22893Stephan Bosch client->remote_port = conn->remote_port;
a05fec120ecd8c4ed6331c42100cba42adf22893Stephan Bosch client->real_local_ip = conn->real_local_ip;
a05fec120ecd8c4ed6331c42100cba42adf22893Stephan Bosch client->real_local_port = conn->real_local_port;
a05fec120ecd8c4ed6331c42100cba42adf22893Stephan Bosch client->real_remote_ip = conn->real_remote_ip;
c12d96f12cac9af464ab2e59046bd59b0c06b4eaTimo Sirainen client->real_remote_port = conn->real_remote_port;
c12d96f12cac9af464ab2e59046bd59b0c06b4eaTimo Sirainen client->listener_name = p_strdup(client->pool, conn->name);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->trusted = client_is_trusted(client);
b6fbc235f981b10333403e2fd6d333fd351c7a3cAki Tuomi
b6fbc235f981b10333403e2fd6d333fd351c7a3cAki Tuomi if (conn->proxied) {
3609e0b9b8fcd1a183a785af690cdcad33c345aaAki Tuomi client->proxied_ssl = conn->proxy.ssl;
b6fbc235f981b10333403e2fd6d333fd351c7a3cAki Tuomi client->secured = conn->proxy.ssl || client->trusted;
9666d130b63653a5a6d5d2f38ca2df72a5f3f7a7Stephan Bosch client->ssl_secured = conn->proxy.ssl;
b6fbc235f981b10333403e2fd6d333fd351c7a3cAki Tuomi client->local_name = conn->proxy.hostname;
b6fbc235f981b10333403e2fd6d333fd351c7a3cAki Tuomi client->client_cert_common_name = conn->proxy.cert_common_name;
b6fbc235f981b10333403e2fd6d333fd351c7a3cAki Tuomi } else {
be6e55ff7c81afdc7ed9b47c6021a4f7827e4407Timo Sirainen client->secured = client->trusted ||
b6fbc235f981b10333403e2fd6d333fd351c7a3cAki Tuomi net_ip_compare(&conn->real_remote_ip, &conn->real_local_ip);
b6fbc235f981b10333403e2fd6d333fd351c7a3cAki Tuomi }
ddbdc644a15f56f4b43596f1b8c0fc196c101445Timo Sirainen client->proxy_ttl = LOGIN_PROXY_TTL;
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen client_open_streams(client);
66ea9eaaa2d7531b3be8f633937628c94d907031Timo Sirainen return client;
66ea9eaaa2d7531b3be8f633937628c94d907031Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
66ea9eaaa2d7531b3be8f633937628c94d907031Timo Sirainenvoid client_init(struct client *client, void **other_sets)
66ea9eaaa2d7531b3be8f633937628c94d907031Timo Sirainen{
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen if (last_client == NULL)
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen last_client = client;
d3d769026fae5d21c2d29614d3bc4579e8d79e81Timo Sirainen DLLIST_PREPEND(&clients, client);
ad004e44be109684521494b5af2ad1da39b8bb27Timo Sirainen clients_count++;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
5a9e240ebf8d0daaf029973973b52e415148070bTimo Sirainen client->to_disconnect =
5a9e240ebf8d0daaf029973973b52e415148070bTimo Sirainen timeout_add(CLIENT_LOGIN_TIMEOUT_MSECS,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_idle_disconnect_timeout, client);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen hook_login_client_allocated(client);
f059a046515f4b2b15a6c2a10a6f12f6166e39a5Timo Sirainen client->v.create(client, other_sets);
66ea9eaaa2d7531b3be8f633937628c94d907031Timo Sirainen client->create_finished = TRUE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (auth_client_is_connected(auth_client))
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen client_notify_auth_ready(client);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen else
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_set_auth_waiting(client);
54533aa265f5c87730022cc7576090bc51370f97Timo Sirainen
54533aa265f5c87730022cc7576090bc51370f97Timo Sirainen login_refresh_proctitle();
ad004e44be109684521494b5af2ad1da39b8bb27Timo Sirainen}
ad004e44be109684521494b5af2ad1da39b8bb27Timo Sirainen
dfafc4ac89195b8cdd48afa619599d5b392ef479Stephan Boschvoid client_disconnect(struct client *client, const char *reason)
ad004e44be109684521494b5af2ad1da39b8bb27Timo Sirainen{
dfafc4ac89195b8cdd48afa619599d5b392ef479Stephan Bosch if (client->disconnected)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return;
dfafc4ac89195b8cdd48afa619599d5b392ef479Stephan Bosch client->disconnected = TRUE;
b045b66988bfbaa2795791e42ee724fae6f0db1cAki Tuomi
1a1159e589def1e32b7dc25397f15146672ef73eTimo Sirainen if (!client->login_success &&
1a1159e589def1e32b7dc25397f15146672ef73eTimo Sirainen !client->no_extra_disconnect_reason && reason != NULL) {
56af9dd10e7e6caeaca64395bad3f882b28ecdffTimo Sirainen const char *extra_reason =
56af9dd10e7e6caeaca64395bad3f882b28ecdffTimo Sirainen client_get_extra_disconnect_reason(client);
56af9dd10e7e6caeaca64395bad3f882b28ecdffTimo Sirainen if (extra_reason[0] != '\0')
56af9dd10e7e6caeaca64395bad3f882b28ecdffTimo Sirainen reason = t_strconcat(reason, " ", extra_reason, NULL);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (reason != NULL)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_log(client, reason);
ad004e44be109684521494b5af2ad1da39b8bb27Timo Sirainen
a117008f03ad9e2d54258b30d3fb03ffa502a448Timo Sirainen if (client->output != NULL)
a117008f03ad9e2d54258b30d3fb03ffa502a448Timo Sirainen o_stream_uncork(client->output);
1312cf655d3ea22c0ab6487ce710ad4060c25905Timo Sirainen if (!client->login_success) {
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen io_remove(&client->io);
ac581db9a4ff22c5f99cf1666a0a1a7f7889e0a2Josef 'Jeff' Sipek ssl_iostream_destroy(&client->ssl_iostream);
cff2942962a11f78d23bcb0a4ed56f67e751819cJosef 'Jeff' Sipek iostream_proxy_unref(&client->iostream_fd_proxy);
1312cf655d3ea22c0ab6487ce710ad4060c25905Timo Sirainen i_stream_close(client->input);
1312cf655d3ea22c0ab6487ce710ad4060c25905Timo Sirainen o_stream_close(client->output);
1312cf655d3ea22c0ab6487ce710ad4060c25905Timo Sirainen i_close_fd(&client->fd);
1312cf655d3ea22c0ab6487ce710ad4060c25905Timo Sirainen } else {
1312cf655d3ea22c0ab6487ce710ad4060c25905Timo Sirainen /* Login was successful. We may now be proxying the connection,
1312cf655d3ea22c0ab6487ce710ad4060c25905Timo Sirainen so don't disconnect the client until client_unref(). */
a7efba62b6235e5efc124cbf702ddeb547ca3665Timo Sirainen if (client->iostream_fd_proxy != NULL) {
a7efba62b6235e5efc124cbf702ddeb547ca3665Timo Sirainen client->fd_proxying = TRUE;
935febe5d151719a9ddf1d2ba25449b19c76be04Timo Sirainen i_assert(client->prev == NULL && client->next == NULL);
a7efba62b6235e5efc124cbf702ddeb547ca3665Timo Sirainen DLLIST_PREPEND(&client_fd_proxies, client);
0256180043b9f55b606b523b775e8b23b1b12f83Timo Sirainen client_fd_proxies_count++;
a7efba62b6235e5efc124cbf702ddeb547ca3665Timo Sirainen }
1312cf655d3ea22c0ab6487ce710ad4060c25905Timo Sirainen }
dfafc4ac89195b8cdd48afa619599d5b392ef479Stephan Bosch}
dfafc4ac89195b8cdd48afa619599d5b392ef479Stephan Bosch
dfafc4ac89195b8cdd48afa619599d5b392ef479Stephan Boschvoid client_destroy(struct client *client, const char *reason)
dfafc4ac89195b8cdd48afa619599d5b392ef479Stephan Bosch{
dfafc4ac89195b8cdd48afa619599d5b392ef479Stephan Bosch i_assert(client->create_finished);
dfafc4ac89195b8cdd48afa619599d5b392ef479Stephan Bosch
dfafc4ac89195b8cdd48afa619599d5b392ef479Stephan Bosch if (client->destroyed)
dfafc4ac89195b8cdd48afa619599d5b392ef479Stephan Bosch return;
dfafc4ac89195b8cdd48afa619599d5b392ef479Stephan Bosch client->destroyed = TRUE;
dfafc4ac89195b8cdd48afa619599d5b392ef479Stephan Bosch
dfafc4ac89195b8cdd48afa619599d5b392ef479Stephan Bosch if (last_client == client)
dfafc4ac89195b8cdd48afa619599d5b392ef479Stephan Bosch last_client = client->prev;
935febe5d151719a9ddf1d2ba25449b19c76be04Timo Sirainen /* remove from clients linked list before it's added to
935febe5d151719a9ddf1d2ba25449b19c76be04Timo Sirainen client_fd_proxies. */
dfafc4ac89195b8cdd48afa619599d5b392ef479Stephan Bosch DLLIST_REMOVE(&clients, client);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
935febe5d151719a9ddf1d2ba25449b19c76be04Timo Sirainen client_disconnect(client, reason);
935febe5d151719a9ddf1d2ba25449b19c76be04Timo Sirainen
935febe5d151719a9ddf1d2ba25449b19c76be04Timo Sirainen pool_unref(&client->preproxy_pool);
935febe5d151719a9ddf1d2ba25449b19c76be04Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (client->master_tag != 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_assert(client->auth_request == NULL);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_assert(client->authenticating);
c7fca6cbb32388556d9f6d8313486cc4e4a3c058Timo Sirainen i_assert(client->refcount > 1);
c7fca6cbb32388556d9f6d8313486cc4e4a3c058Timo Sirainen client->authenticating = FALSE;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen master_auth_request_abort(master_auth, client->master_tag);
c7fca6cbb32388556d9f6d8313486cc4e4a3c058Timo Sirainen client->refcount--;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen } else if (client->auth_request != NULL) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_assert(client->authenticating);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen sasl_server_auth_abort(client);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen } else {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_assert(!client->authenticating);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&client->to_disconnect);
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&client->to_auth_waiting);
e9fbe5e18b798728041b7e2ffc6c4fa964fc35a3Josef 'Jeff' Sipek str_free(&client->auth_response);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (client->proxy_password != NULL) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen safe_memset(client->proxy_password, 0,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen strlen(client->proxy_password));
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_free_and_null(client->proxy_password);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen if (client->proxy_sasl_client != NULL)
de754cb78f75e8b3b994cddafe41c9ed1467c33dTimo Sirainen dsasl_client_free(&client->proxy_sasl_client);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (client->login_proxy != NULL)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen login_proxy_free(&client->login_proxy);
ab90f702ceedb7ba445a9a592be0b213b27cbafaStephan Bosch if (client->v.destroy != NULL)
ab90f702ceedb7ba445a9a592be0b213b27cbafaStephan Bosch client->v.destroy(client);
2aac7ca853f63b62ea79ef8eae9ded83ed6063a5Timo Sirainen if (client_unref(&client) && initial_service_count == 1) {
4de2a17e0a2aed3b57a6c1057329b6a132b56ae2Timo Sirainen /* as soon as this connection is done with proxying
4de2a17e0a2aed3b57a6c1057329b6a132b56ae2Timo Sirainen (or whatever), the process will die. there's no need for
2aac7ca853f63b62ea79ef8eae9ded83ed6063a5Timo Sirainen authentication anymore, so close the connection.
2aac7ca853f63b62ea79ef8eae9ded83ed6063a5Timo Sirainen do this only with initial service_count=1, in case there
2aac7ca853f63b62ea79ef8eae9ded83ed6063a5Timo Sirainen are other clients with pending authentications */
9ddd3d7d8651985e373a6c48e0ddc76b8a4ef1c7Timo Sirainen auth_client_disconnect(auth_client, "unnecessary connection");
4de2a17e0a2aed3b57a6c1057329b6a132b56ae2Timo Sirainen }
5d2e7ec2ea725c8a6a63f56b771e746f93e782ecTimo Sirainen login_client_destroyed();
54533aa265f5c87730022cc7576090bc51370f97Timo Sirainen login_refresh_proctitle();
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenvoid client_destroy_success(struct client *client, const char *reason)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->login_success = TRUE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_destroy(client, reason);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenvoid client_ref(struct client *client)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->refcount++;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
ec23e16ed879e289d12c6e1a5f9745dd3979004aTimo Sirainenbool client_unref(struct client **_client)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
ec23e16ed879e289d12c6e1a5f9745dd3979004aTimo Sirainen struct client *client = *_client;
ec23e16ed879e289d12c6e1a5f9745dd3979004aTimo Sirainen
b833824981bc75af72adb844f8a4a992bd2f3ad3Timo Sirainen *_client = NULL;
b833824981bc75af72adb844f8a4a992bd2f3ad3Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_assert(client->refcount > 0);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (--client->refcount > 0)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return TRUE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
66ea9eaaa2d7531b3be8f633937628c94d907031Timo Sirainen if (!client->create_finished) {
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen i_stream_unref(&client->input);
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen o_stream_unref(&client->output);
66ea9eaaa2d7531b3be8f633937628c94d907031Timo Sirainen pool_unref(&client->preproxy_pool);
66ea9eaaa2d7531b3be8f633937628c94d907031Timo Sirainen pool_unref(&client->pool);
66ea9eaaa2d7531b3be8f633937628c94d907031Timo Sirainen return FALSE;
66ea9eaaa2d7531b3be8f633937628c94d907031Timo Sirainen }
66ea9eaaa2d7531b3be8f633937628c94d907031Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_assert(client->destroyed);
ec23e16ed879e289d12c6e1a5f9745dd3979004aTimo Sirainen i_assert(client->login_proxy == NULL);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
b84eff65e25ae86dfd6f798386577209b94838c6Timo Sirainen if (client->v.free != NULL)
b84eff65e25ae86dfd6f798386577209b94838c6Timo Sirainen client->v.free(client);
b84eff65e25ae86dfd6f798386577209b94838c6Timo Sirainen
ac581db9a4ff22c5f99cf1666a0a1a7f7889e0a2Josef 'Jeff' Sipek ssl_iostream_destroy(&client->ssl_iostream);
cff2942962a11f78d23bcb0a4ed56f67e751819cJosef 'Jeff' Sipek iostream_proxy_unref(&client->iostream_fd_proxy);
a7efba62b6235e5efc124cbf702ddeb547ca3665Timo Sirainen if (client->fd_proxying) {
a7efba62b6235e5efc124cbf702ddeb547ca3665Timo Sirainen DLLIST_REMOVE(&client_fd_proxies, client);
0256180043b9f55b606b523b775e8b23b1b12f83Timo Sirainen i_assert(client_fd_proxies_count > 0);
0256180043b9f55b606b523b775e8b23b1b12f83Timo Sirainen client_fd_proxies_count--;
a7efba62b6235e5efc124cbf702ddeb547ca3665Timo Sirainen }
204ee6ed414f5e4eeb6f6c10763b55daf56f11acJosef 'Jeff' Sipek i_stream_unref(&client->input);
204ee6ed414f5e4eeb6f6c10763b55daf56f11acJosef 'Jeff' Sipek o_stream_unref(&client->output);
1312cf655d3ea22c0ab6487ce710ad4060c25905Timo Sirainen i_close_fd(&client->fd);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
6303191abcb37164f435ccdc56e9dbddf1288851Timo Sirainen i_free(client->proxy_user);
6303191abcb37164f435ccdc56e9dbddf1288851Timo Sirainen i_free(client->proxy_master_user);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_free(client->virtual_user);
c7eb1ffb7c73cb5d9c1316bbecd02947441a40d4Timo Sirainen i_free(client->virtual_user_orig);
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen i_free(client->virtual_auth_user);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_free(client->auth_mech_name);
b6b7a17731a917958b6479920b3fac5ca991db6aTimo Sirainen i_free(client->master_data_prefix);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen pool_unref(&client->pool);
ec23e16ed879e289d12c6e1a5f9745dd3979004aTimo Sirainen
54533aa265f5c87730022cc7576090bc51370f97Timo Sirainen i_assert(clients_count > 0);
54533aa265f5c87730022cc7576090bc51370f97Timo Sirainen clients_count--;
54533aa265f5c87730022cc7576090bc51370f97Timo Sirainen
ec23e16ed879e289d12c6e1a5f9745dd3979004aTimo Sirainen master_service_client_connection_destroyed(master_service);
54533aa265f5c87730022cc7576090bc51370f97Timo Sirainen login_refresh_proctitle();
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return FALSE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
b84eff65e25ae86dfd6f798386577209b94838c6Timo Sirainenvoid client_common_default_free(struct client *client ATTR_UNUSED)
b84eff65e25ae86dfd6f798386577209b94838c6Timo Sirainen{
b84eff65e25ae86dfd6f798386577209b94838c6Timo Sirainen}
b84eff65e25ae86dfd6f798386577209b94838c6Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenvoid client_destroy_oldest(void)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct client *client;
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen if (last_client == NULL) {
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen /* we have no clients */
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen return;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen /* destroy the last client that hasn't successfully authenticated yet.
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen this is usually the last client, but don't kill it if it's just
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen waiting for master to finish its job. */
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen for (client = last_client; client != NULL; client = client->prev) {
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen if (client->master_tag == 0)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen break;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen if (client == NULL)
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen client = last_client;
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen client_notify_disconnect(client, CLIENT_DISCONNECT_RESOURCE_CONSTRAINT,
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen "Connection queue full");
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen client_destroy(client, "Disconnected: Connection queue full");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
717bb0dbaf4bd3f745669570647845e6d493bfe0Timo Sirainenvoid clients_destroy_all_reason(const char *reason)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct client *client, *next;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen for (client = clients; client != NULL; client = next) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen next = client->next;
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen client_notify_disconnect(client,
73f021723bffa0841bbdf371882b463a449f1ea9Timo Sirainen CLIENT_DISCONNECT_SYSTEM_SHUTDOWN, reason);
717bb0dbaf4bd3f745669570647845e6d493bfe0Timo Sirainen client_destroy(client, reason);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
717bb0dbaf4bd3f745669570647845e6d493bfe0Timo Sirainenvoid clients_destroy_all(void)
717bb0dbaf4bd3f745669570647845e6d493bfe0Timo Sirainen{
717bb0dbaf4bd3f745669570647845e6d493bfe0Timo Sirainen clients_destroy_all_reason("Disconnected: Shutting down");
717bb0dbaf4bd3f745669570647845e6d493bfe0Timo Sirainen}
717bb0dbaf4bd3f745669570647845e6d493bfe0Timo Sirainen
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainenstatic int client_sni_callback(const char *name, const char **error_r,
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen void *context)
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen{
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen struct client *client = context;
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen struct ssl_iostream_context *ssl_ctx;
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen struct ssl_iostream_settings ssl_set;
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen void **other_sets;
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen const char *error;
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen if (client->ssl_servername_settings_read)
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen return 0;
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen client->ssl_servername_settings_read = TRUE;
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen client->local_name = p_strdup(client->pool, name);
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen client->set = login_settings_read(client->pool, &client->local_ip,
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen &client->ip, name,
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen &client->ssl_set, &other_sets);
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen master_service_ssl_settings_to_iostream_set(client->ssl_set,
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen pool_datastack_create(),
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen MASTER_SERVICE_SSL_SETTINGS_TYPE_SERVER, &ssl_set);
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen if (ssl_iostream_server_context_cache_get(&ssl_set, &ssl_ctx, &error) < 0) {
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen *error_r = t_strdup_printf(
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen "Failed to initialize SSL server context: %s", error);
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen return -1;
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen }
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen ssl_iostream_change_context(client->ssl_iostream, ssl_ctx);
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen ssl_iostream_context_unref(&ssl_ctx);
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen return 0;
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen}
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen
b1485f2691de41ed7b5f96cebda2ebcb69a5e22fTimo Sirainenint client_init_ssl(struct client *client)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen struct ssl_iostream_context *ssl_ctx;
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen struct ssl_iostream_settings ssl_set;
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen const char *error;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
b1485f2691de41ed7b5f96cebda2ebcb69a5e22fTimo Sirainen i_assert(client->fd != -1);
b1485f2691de41ed7b5f96cebda2ebcb69a5e22fTimo Sirainen
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen master_service_ssl_settings_to_iostream_set(client->ssl_set,
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen pool_datastack_create(),
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen MASTER_SERVICE_SSL_SETTINGS_TYPE_SERVER, &ssl_set);
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen /* If the client cert is invalid, we'll reply NO to the login
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen command. */
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen ssl_set.allow_invalid_cert = TRUE;
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen if (ssl_iostream_server_context_cache_get(&ssl_set, &ssl_ctx, &error) < 0) {
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen client_log_err(client, t_strdup_printf(
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen "Failed to initialize SSL server context: %s", error));
b1485f2691de41ed7b5f96cebda2ebcb69a5e22fTimo Sirainen return -1;
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen }
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen if (io_stream_create_ssl_server(ssl_ctx, &ssl_set,
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen &client->input, &client->output,
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen &client->ssl_iostream, &error) < 0) {
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen client_log_err(client, t_strdup_printf(
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen "Failed to initialize SSL connection: %s", error));
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen ssl_iostream_context_unref(&ssl_ctx);
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen return -1;
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen }
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen ssl_iostream_context_unref(&ssl_ctx);
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen ssl_iostream_set_sni_callback(client->ssl_iostream,
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen client_sni_callback, client);
b1485f2691de41ed7b5f96cebda2ebcb69a5e22fTimo Sirainen
b1485f2691de41ed7b5f96cebda2ebcb69a5e22fTimo Sirainen client->tls = TRUE;
b1485f2691de41ed7b5f96cebda2ebcb69a5e22fTimo Sirainen client->secured = TRUE;
9666d130b63653a5a6d5d2f38ca2df72a5f3f7a7Stephan Bosch client->ssl_secured = TRUE;
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen if (client->starttls) {
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen io_remove(&client->io);
a1852ab4cf0a942a3fcf4ca5636a7932ebcc7970Stephan Bosch if (!client_does_custom_io(client)) {
a1852ab4cf0a942a3fcf4ca5636a7932ebcc7970Stephan Bosch client->io = io_add_istream(client->input,
a1852ab4cf0a942a3fcf4ca5636a7932ebcc7970Stephan Bosch client_input, client);
a1852ab4cf0a942a3fcf4ca5636a7932ebcc7970Stephan Bosch }
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen }
b1485f2691de41ed7b5f96cebda2ebcb69a5e22fTimo Sirainen return 0;
b1485f2691de41ed7b5f96cebda2ebcb69a5e22fTimo Sirainen}
b1485f2691de41ed7b5f96cebda2ebcb69a5e22fTimo Sirainen
b1485f2691de41ed7b5f96cebda2ebcb69a5e22fTimo Sirainenstatic void client_start_tls(struct client *client)
b1485f2691de41ed7b5f96cebda2ebcb69a5e22fTimo Sirainen{
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen client->starttls = TRUE;
b1485f2691de41ed7b5f96cebda2ebcb69a5e22fTimo Sirainen if (client_init_ssl(client) < 0) {
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen client_notify_disconnect(client,
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen CLIENT_DISCONNECT_INTERNAL_ERROR,
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen "TLS initialization failed.");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_destroy(client,
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen "Disconnected: TLS initialization failed.");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
54533aa265f5c87730022cc7576090bc51370f97Timo Sirainen login_refresh_proctitle();
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->v.starttls(client);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic int client_output_starttls(struct client *client)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen int ret;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if ((ret = o_stream_flush(client->output)) < 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_destroy(client, "Disconnected");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return 1;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (ret > 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen o_stream_unset_flush_callback(client->output);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_start_tls(client);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return 1;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenvoid client_cmd_starttls(struct client *client)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (client->tls) {
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen client->v.notify_starttls(client, FALSE, "TLS is already active.");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
6a9e034441607c0c5a61858ff559af4615ac31caTimo Sirainen if (!client_is_tls_enabled(client)) {
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen client->v.notify_starttls(client, FALSE, "TLS support isn't enabled.");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* remove input handler, SSL proxy gives us a new fd. we also have to
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen remove it in case we have to wait for buffer to be flushed */
5f1d689131a75c39f064cbd4202373e7edf78f18Josef 'Jeff' Sipek io_remove(&client->io);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen client->v.notify_starttls(client, TRUE, "Begin TLS negotiation now.");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* uncork the old fd */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen o_stream_uncork(client->output);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (o_stream_flush(client->output) <= 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* the buffer has to be flushed */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen o_stream_set_flush_pending(client->output, TRUE);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen o_stream_set_flush_callback(client->output,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_output_starttls, client);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen } else {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_start_tls(client);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
ad004e44be109684521494b5af2ad1da39b8bb27Timo Sirainen}
ad004e44be109684521494b5af2ad1da39b8bb27Timo Sirainen
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainenstatic void
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Siraineniostream_fd_proxy_finished(enum iostream_proxy_side side ATTR_UNUSED,
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen enum iostream_proxy_status status ATTR_UNUSED,
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen struct client *client)
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen{
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen /* Destroy the proxy now. The other side of the proxy is still
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen unfinished and we don't want to get back here and unreference
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen the client twice. */
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen iostream_proxy_unref(&client->iostream_fd_proxy);
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen client_unref(&client);
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen}
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainenint client_get_plaintext_fd(struct client *client, int *fd_r, bool *close_fd_r)
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen{
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen int fds[2];
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen if (!client->tls) {
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen /* Plaintext connection - We can send the fd directly to
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen the post-login process without any proxying. */
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen *fd_r = client->fd;
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen *close_fd_r = FALSE;
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen return 0;
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen }
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen /* We'll have to start proxying from now on until either side
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen disconnects. Create a socketpair where login process is proxying on
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen one side and the other side is sent to the post-login process. */
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) {
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen client_log_err(client, t_strdup_printf("socketpair() failed: %m"));
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen return -1;
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen }
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen fd_set_nonblock(fds[0], TRUE);
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen fd_set_nonblock(fds[1], TRUE);
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen struct ostream *output = o_stream_create_fd(fds[0], IO_BLOCK_SIZE);
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen struct istream *input =
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen i_stream_create_fd_autoclose(&fds[0], IO_BLOCK_SIZE);
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen o_stream_set_no_error_handling(output, TRUE);
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen i_assert(client->io == NULL);
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen client_ref(client);
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen client->iostream_fd_proxy =
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen iostream_proxy_create(input, output,
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen client->input, client->output);
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen i_stream_unref(&input);
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen o_stream_unref(&output);
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen iostream_proxy_set_completion_callback(client->iostream_fd_proxy,
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen iostream_fd_proxy_finished,
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen client);
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen iostream_proxy_start(client->iostream_fd_proxy);
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen *fd_r = fds[1];
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen *close_fd_r = TRUE;
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen return 0;
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen}
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen
ad004e44be109684521494b5af2ad1da39b8bb27Timo Sirainenunsigned int clients_get_count(void)
ad004e44be109684521494b5af2ad1da39b8bb27Timo Sirainen{
ad004e44be109684521494b5af2ad1da39b8bb27Timo Sirainen return clients_count;
ad004e44be109684521494b5af2ad1da39b8bb27Timo Sirainen}
ad004e44be109684521494b5af2ad1da39b8bb27Timo Sirainen
0256180043b9f55b606b523b775e8b23b1b12f83Timo Sirainenunsigned int clients_get_fd_proxies_count(void)
0256180043b9f55b606b523b775e8b23b1b12f83Timo Sirainen{
0256180043b9f55b606b523b775e8b23b1b12f83Timo Sirainen return client_fd_proxies_count;
0256180043b9f55b606b523b775e8b23b1b12f83Timo Sirainen}
0256180043b9f55b606b523b775e8b23b1b12f83Timo Sirainen
0256180043b9f55b606b523b775e8b23b1b12f83Timo Sirainenstruct client *clients_get_first_fd_proxy(void)
0256180043b9f55b606b523b775e8b23b1b12f83Timo Sirainen{
0256180043b9f55b606b523b775e8b23b1b12f83Timo Sirainen return client_fd_proxies;
0256180043b9f55b606b523b775e8b23b1b12f83Timo Sirainen}
0256180043b9f55b606b523b775e8b23b1b12f83Timo Sirainen
c4ec7cb598805b1387dc3aab59ec8f32d8cc24e1Timo Sirainenvoid client_add_forward_field(struct client *client, const char *key,
c4ec7cb598805b1387dc3aab59ec8f32d8cc24e1Timo Sirainen const char *value)
c4ec7cb598805b1387dc3aab59ec8f32d8cc24e1Timo Sirainen{
c4ec7cb598805b1387dc3aab59ec8f32d8cc24e1Timo Sirainen if (client->forward_fields == NULL)
c4ec7cb598805b1387dc3aab59ec8f32d8cc24e1Timo Sirainen client->forward_fields = str_new(client->preproxy_pool, 32);
c4ec7cb598805b1387dc3aab59ec8f32d8cc24e1Timo Sirainen else
c4ec7cb598805b1387dc3aab59ec8f32d8cc24e1Timo Sirainen str_append_c(client->forward_fields, '\t');
c4ec7cb598805b1387dc3aab59ec8f32d8cc24e1Timo Sirainen /* prefixing is done by auth process */
c4ec7cb598805b1387dc3aab59ec8f32d8cc24e1Timo Sirainen str_append_tabescaped(client->forward_fields, key);
c4ec7cb598805b1387dc3aab59ec8f32d8cc24e1Timo Sirainen str_append_c(client->forward_fields, '=');
c4ec7cb598805b1387dc3aab59ec8f32d8cc24e1Timo Sirainen str_append_tabescaped(client->forward_fields, value);
c4ec7cb598805b1387dc3aab59ec8f32d8cc24e1Timo Sirainen}
c4ec7cb598805b1387dc3aab59ec8f32d8cc24e1Timo Sirainen
b55f914c0ade77252cfd798ea8eb9a84bda56315Timo Sirainenconst char *client_get_session_id(struct client *client)
b55f914c0ade77252cfd798ea8eb9a84bda56315Timo Sirainen{
b55f914c0ade77252cfd798ea8eb9a84bda56315Timo Sirainen buffer_t *buf, *base64_buf;
b55f914c0ade77252cfd798ea8eb9a84bda56315Timo Sirainen struct timeval tv;
b55f914c0ade77252cfd798ea8eb9a84bda56315Timo Sirainen uint64_t timestamp;
b55f914c0ade77252cfd798ea8eb9a84bda56315Timo Sirainen unsigned int i;
b55f914c0ade77252cfd798ea8eb9a84bda56315Timo Sirainen
b55f914c0ade77252cfd798ea8eb9a84bda56315Timo Sirainen if (client->session_id != NULL)
b55f914c0ade77252cfd798ea8eb9a84bda56315Timo Sirainen return client->session_id;
b55f914c0ade77252cfd798ea8eb9a84bda56315Timo Sirainen
c147bff818798a979d93537f72f5c1f68f5d5ba8Aki Tuomi buf = t_buffer_create(24);
c147bff818798a979d93537f72f5c1f68f5d5ba8Aki Tuomi base64_buf = t_buffer_create(24*2);
b55f914c0ade77252cfd798ea8eb9a84bda56315Timo Sirainen
b55f914c0ade77252cfd798ea8eb9a84bda56315Timo Sirainen if (gettimeofday(&tv, NULL) < 0)
b55f914c0ade77252cfd798ea8eb9a84bda56315Timo Sirainen i_fatal("gettimeofday(): %m");
b55f914c0ade77252cfd798ea8eb9a84bda56315Timo Sirainen timestamp = tv.tv_usec + (long long)tv.tv_sec * 1000ULL*1000ULL;
b55f914c0ade77252cfd798ea8eb9a84bda56315Timo Sirainen
b55f914c0ade77252cfd798ea8eb9a84bda56315Timo Sirainen /* add lowest 48 bits of the timestamp. this gives us a bit less than
b55f914c0ade77252cfd798ea8eb9a84bda56315Timo Sirainen 9 years until it wraps */
b55f914c0ade77252cfd798ea8eb9a84bda56315Timo Sirainen for (i = 0; i < 48; i += 8)
b55f914c0ade77252cfd798ea8eb9a84bda56315Timo Sirainen buffer_append_c(buf, (timestamp >> i) & 0xff);
b55f914c0ade77252cfd798ea8eb9a84bda56315Timo Sirainen
b55f914c0ade77252cfd798ea8eb9a84bda56315Timo Sirainen buffer_append_c(buf, client->remote_port & 0xff);
a7d14da6cef3cfe26df5d039088ddd186c8aaedfTimo Sirainen buffer_append_c(buf, (client->remote_port >> 8) & 0xff);
b55f914c0ade77252cfd798ea8eb9a84bda56315Timo Sirainen if (IPADDR_IS_V6(&client->ip))
b55f914c0ade77252cfd798ea8eb9a84bda56315Timo Sirainen buffer_append(buf, &client->ip.u.ip6, sizeof(client->ip.u.ip6));
b55f914c0ade77252cfd798ea8eb9a84bda56315Timo Sirainen else
b55f914c0ade77252cfd798ea8eb9a84bda56315Timo Sirainen buffer_append(buf, &client->ip.u.ip4, sizeof(client->ip.u.ip4));
b55f914c0ade77252cfd798ea8eb9a84bda56315Timo Sirainen base64_encode(buf->data, buf->used, base64_buf);
b55f914c0ade77252cfd798ea8eb9a84bda56315Timo Sirainen client->session_id = p_strdup(client->pool, str_c(base64_buf));
b55f914c0ade77252cfd798ea8eb9a84bda56315Timo Sirainen return client->session_id;
b55f914c0ade77252cfd798ea8eb9a84bda56315Timo Sirainen}
b55f914c0ade77252cfd798ea8eb9a84bda56315Timo Sirainen
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainenstatic struct var_expand_table login_var_expand_empty_tab[] = {
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen { 'u', NULL, "user" },
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen { 'n', NULL, "username" },
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen { 'd', NULL, "domain" },
c7eb1ffb7c73cb5d9c1316bbecd02947441a40d4Timo Sirainen
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen { 's', NULL, "service" },
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen { 'h', NULL, "home" },
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen { 'l', NULL, "lip" },
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen { 'r', NULL, "rip" },
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen { 'p', NULL, "pid" },
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen { 'm', NULL, "mech" },
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen { 'a', NULL, "lport" },
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen { 'b', NULL, "rport" },
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen { 'c', NULL, "secured" },
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen { 'k', NULL, "ssl_security" },
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen { 'e', NULL, "mail_pid" },
b55f914c0ade77252cfd798ea8eb9a84bda56315Timo Sirainen { '\0', NULL, "session" },
325d17cdbb7a338f7c413788f5e8e42d2e80a7f8Timo Sirainen { '\0', NULL, "real_lip" },
da62041ae41e58c9e3ef91bd46c15484390c8247Timo Sirainen { '\0', NULL, "real_rip" },
325d17cdbb7a338f7c413788f5e8e42d2e80a7f8Timo Sirainen { '\0', NULL, "real_lport" },
325d17cdbb7a338f7c413788f5e8e42d2e80a7f8Timo Sirainen { '\0', NULL, "real_rport" },
c7eb1ffb7c73cb5d9c1316bbecd02947441a40d4Timo Sirainen { '\0', NULL, "orig_user" },
c7eb1ffb7c73cb5d9c1316bbecd02947441a40d4Timo Sirainen { '\0', NULL, "orig_username" },
c7eb1ffb7c73cb5d9c1316bbecd02947441a40d4Timo Sirainen { '\0', NULL, "orig_domain" },
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen { '\0', NULL, "auth_user" },
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen { '\0', NULL, "auth_username" },
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen { '\0', NULL, "auth_domain" },
c12d96f12cac9af464ab2e59046bd59b0c06b4eaTimo Sirainen { '\0', NULL, "listener" },
290b91ad6f5ea9e44b2d86b68dd80f0313cd2c57Aki Tuomi { '\0', NULL, "local_name" },
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen { '\0', NULL, NULL }
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen};
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainenstatic void
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainenget_var_expand_users(struct var_expand_table *tab, const char *user)
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen{
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen unsigned int i;
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen tab[0].value = user;
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen tab[1].value = t_strcut(user, '@');
4b1781e4c64be52e25b5994e5242dbe696cc7d29Timo Sirainen tab[2].value = i_strchr_to_next(user, '@');
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen for (i = 0; i < 3; i++)
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen tab[i].value = str_sanitize(tab[i].value, 80);
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen}
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainenstatic const struct var_expand_table *
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainenget_var_expand_table(struct client *client)
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen{
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen struct var_expand_table *tab;
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen
0175d37a5ae5a4d146ca41b684bd38d9b03683cbMartti Rannanjärvi tab = t_malloc_no0(sizeof(login_var_expand_empty_tab));
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen memcpy(tab, login_var_expand_empty_tab,
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen sizeof(login_var_expand_empty_tab));
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen if (client->virtual_user != NULL)
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen get_var_expand_users(tab, client->virtual_user);
5a250816ffc4cc5db203f9410ea99b6601c7b91aTimo Sirainen tab[3].value = login_binary->protocol;
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen tab[4].value = getenv("HOME");
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen tab[5].value = net_ip2addr(&client->local_ip);
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen tab[6].value = net_ip2addr(&client->ip);
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen tab[7].value = my_pid;
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen tab[8].value = client->auth_mech_name == NULL ? NULL :
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen str_sanitize(client->auth_mech_name, MAX_MECH_NAME);
12cf3d0e03fc70fb0c8b91bc8fd83b4e14d7cdefTimo Sirainen tab[9].value = dec2str(client->local_port);
12cf3d0e03fc70fb0c8b91bc8fd83b4e14d7cdefTimo Sirainen tab[10].value = dec2str(client->remote_port);
4ead43ecc06d10047998966c4dc0b142ecce4b66Timo Sirainen if (!client->tls) {
12cf3d0e03fc70fb0c8b91bc8fd83b4e14d7cdefTimo Sirainen tab[11].value = client->secured ? "secured" : NULL;
4e35bae013cee5a06d281776a347b534b958aaa4Timo Sirainen tab[12].value = "";
3609e0b9b8fcd1a183a785af690cdcad33c345aaAki Tuomi } else if (client->proxied_ssl) {
3609e0b9b8fcd1a183a785af690cdcad33c345aaAki Tuomi tab[11].value = "TLS";
3609e0b9b8fcd1a183a785af690cdcad33c345aaAki Tuomi tab[12].value = "(proxied)";
4ead43ecc06d10047998966c4dc0b142ecce4b66Timo Sirainen } else {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const char *ssl_state =
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen ssl_iostream_is_handshaked(client->ssl_iostream) ?
bb8d0ec26bdd548624d7a7424071cca693b72f55Timo Sirainen "TLS" : "TLS handshaking";
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const char *ssl_error =
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen ssl_iostream_get_last_error(client->ssl_iostream);
bb8d0ec26bdd548624d7a7424071cca693b72f55Timo Sirainen
bb8d0ec26bdd548624d7a7424071cca693b72f55Timo Sirainen tab[11].value = ssl_error == NULL ? ssl_state :
bb8d0ec26bdd548624d7a7424071cca693b72f55Timo Sirainen t_strdup_printf("%s: %s", ssl_state, ssl_error);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen tab[12].value =
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen ssl_iostream_get_security_string(client->ssl_iostream);
4ead43ecc06d10047998966c4dc0b142ecce4b66Timo Sirainen }
506e41a4efbc7f4bba93cd295ca4dba18ed3cf09Timo Sirainen tab[13].value = client->mail_pid == 0 ? "" :
506e41a4efbc7f4bba93cd295ca4dba18ed3cf09Timo Sirainen dec2str(client->mail_pid);
b55f914c0ade77252cfd798ea8eb9a84bda56315Timo Sirainen tab[14].value = client_get_session_id(client);
325d17cdbb7a338f7c413788f5e8e42d2e80a7f8Timo Sirainen tab[15].value = net_ip2addr(&client->real_local_ip);
325d17cdbb7a338f7c413788f5e8e42d2e80a7f8Timo Sirainen tab[16].value = net_ip2addr(&client->real_remote_ip);
325d17cdbb7a338f7c413788f5e8e42d2e80a7f8Timo Sirainen tab[17].value = dec2str(client->real_local_port);
325d17cdbb7a338f7c413788f5e8e42d2e80a7f8Timo Sirainen tab[18].value = dec2str(client->real_remote_port);
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen if (client->virtual_user_orig != NULL)
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen get_var_expand_users(tab+19, client->virtual_user_orig);
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen else {
c7eb1ffb7c73cb5d9c1316bbecd02947441a40d4Timo Sirainen tab[19].value = tab[0].value;
c7eb1ffb7c73cb5d9c1316bbecd02947441a40d4Timo Sirainen tab[20].value = tab[1].value;
c7eb1ffb7c73cb5d9c1316bbecd02947441a40d4Timo Sirainen tab[21].value = tab[2].value;
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen }
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen if (client->virtual_auth_user != NULL)
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen get_var_expand_users(tab+22, client->virtual_auth_user);
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen else {
dd620bc3687f995c483152115590e769094e77d5Timo Sirainen tab[22].value = tab[19].value;
dd620bc3687f995c483152115590e769094e77d5Timo Sirainen tab[23].value = tab[20].value;
dd620bc3687f995c483152115590e769094e77d5Timo Sirainen tab[24].value = tab[21].value;
c7eb1ffb7c73cb5d9c1316bbecd02947441a40d4Timo Sirainen }
c12d96f12cac9af464ab2e59046bd59b0c06b4eaTimo Sirainen tab[25].value = client->listener_name;
290b91ad6f5ea9e44b2d86b68dd80f0313cd2c57Aki Tuomi tab[26].value = str_sanitize(client->local_name, 256);
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen return tab;
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen}
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainenstatic bool have_username_key(const char *str)
1d4f710106fb498750456724628da6063e012e6dTimo Sirainen{
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen char key;
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen for (; *str != '\0'; str++) {
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen if (str[0] == '%' && str[1] != '\0') {
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen str++;
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen key = var_get_key(str);
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen if (key == 'u' || key == 'n')
88c92ce2caa8f9fa34708471c6ed4e974d5a7953Timo Sirainen return TRUE;
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen }
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen }
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen return FALSE;
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen}
1d4f710106fb498750456724628da6063e012e6dTimo Sirainen
bcf1cf2afb9692b0db555e6ecf662a2fbd19793dTimo Sirainenstatic int
bcf1cf2afb9692b0db555e6ecf662a2fbd19793dTimo Sirainenclient_var_expand_func_passdb(const char *data, void *context,
bcf1cf2afb9692b0db555e6ecf662a2fbd19793dTimo Sirainen const char **value_r,
bcf1cf2afb9692b0db555e6ecf662a2fbd19793dTimo Sirainen const char **error_r ATTR_UNUSED)
2dfd08e8aa16dfcc975d8a62bc8d20b2ef849d71Timo Sirainen{
2dfd08e8aa16dfcc975d8a62bc8d20b2ef849d71Timo Sirainen struct client *client = context;
2dfd08e8aa16dfcc975d8a62bc8d20b2ef849d71Timo Sirainen const char *field_name = data;
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen unsigned int i;
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen size_t field_name_len;
2dfd08e8aa16dfcc975d8a62bc8d20b2ef849d71Timo Sirainen
bcf1cf2afb9692b0db555e6ecf662a2fbd19793dTimo Sirainen *value_r = NULL;
bcf1cf2afb9692b0db555e6ecf662a2fbd19793dTimo Sirainen
2dfd08e8aa16dfcc975d8a62bc8d20b2ef849d71Timo Sirainen if (client->auth_passdb_args == NULL)
bcf1cf2afb9692b0db555e6ecf662a2fbd19793dTimo Sirainen return 1;
2dfd08e8aa16dfcc975d8a62bc8d20b2ef849d71Timo Sirainen
2dfd08e8aa16dfcc975d8a62bc8d20b2ef849d71Timo Sirainen field_name_len = strlen(field_name);
2dfd08e8aa16dfcc975d8a62bc8d20b2ef849d71Timo Sirainen for (i = 0; client->auth_passdb_args[i] != NULL; i++) {
2dfd08e8aa16dfcc975d8a62bc8d20b2ef849d71Timo Sirainen if (strncmp(client->auth_passdb_args[i], field_name,
2dfd08e8aa16dfcc975d8a62bc8d20b2ef849d71Timo Sirainen field_name_len) == 0 &&
bcf1cf2afb9692b0db555e6ecf662a2fbd19793dTimo Sirainen client->auth_passdb_args[i][field_name_len] == '=') {
bcf1cf2afb9692b0db555e6ecf662a2fbd19793dTimo Sirainen *value_r = client->auth_passdb_args[i] + field_name_len+1;
bcf1cf2afb9692b0db555e6ecf662a2fbd19793dTimo Sirainen return 1;
bcf1cf2afb9692b0db555e6ecf662a2fbd19793dTimo Sirainen }
2dfd08e8aa16dfcc975d8a62bc8d20b2ef849d71Timo Sirainen }
bcf1cf2afb9692b0db555e6ecf662a2fbd19793dTimo Sirainen return 1;
2dfd08e8aa16dfcc975d8a62bc8d20b2ef849d71Timo Sirainen}
2dfd08e8aa16dfcc975d8a62bc8d20b2ef849d71Timo Sirainen
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainenstatic const char *
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainenclient_get_log_str(struct client *client, const char *msg)
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen{
2dfd08e8aa16dfcc975d8a62bc8d20b2ef849d71Timo Sirainen static const struct var_expand_func_table func_table[] = {
2dfd08e8aa16dfcc975d8a62bc8d20b2ef849d71Timo Sirainen { "passdb", client_var_expand_func_passdb },
2dfd08e8aa16dfcc975d8a62bc8d20b2ef849d71Timo Sirainen { NULL, NULL }
2dfd08e8aa16dfcc975d8a62bc8d20b2ef849d71Timo Sirainen };
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen static bool expand_error_logged = FALSE;
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen const struct var_expand_table *var_expand_table;
97db4761382024093f441e4bc78ba8b6a056504dTimo Sirainen char *const *e;
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen const char *error;
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen string_t *str, *str2;
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen unsigned int pos;
1d4f710106fb498750456724628da6063e012e6dTimo Sirainen
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen var_expand_table = get_var_expand_table(client);
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen str = t_str_new(256);
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen str2 = t_str_new(128);
97db4761382024093f441e4bc78ba8b6a056504dTimo Sirainen for (e = client->set->log_format_elements_split; *e != NULL; e++) {
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen pos = str_len(str);
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen if (var_expand_with_funcs(str, *e, var_expand_table,
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen func_table, client, &error) <= 0 &&
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen !expand_error_logged) {
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen i_error("Failed to expand log_format_elements=%s: %s",
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen *e, error);
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen expand_error_logged = TRUE;
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen }
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen if (have_username_key(*e)) {
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen /* username is added even if it's empty */
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen } else {
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen str_truncate(str2, 0);
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen if (var_expand(str2, *e, login_var_expand_empty_tab,
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen &error) <= 0) {
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen /* we just logged this error above. no need
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen to do it again. */
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen }
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen if (strcmp(str_c(str)+pos, str_c(str2)) == 0) {
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen /* empty %variables, don't add */
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen str_truncate(str, pos);
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen continue;
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen }
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen }
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen if (str_len(str) > 0)
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen str_append(str, ", ");
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen }
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen if (str_len(str) > 0)
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen str_truncate(str, str_len(str)-2);
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen
acfda38b75d0f0e899ef692fef01593bd56ed85eTimo Sirainen const struct var_expand_table tab[3] = {
acfda38b75d0f0e899ef692fef01593bd56ed85eTimo Sirainen { 's', t_strdup(str_c(str)), NULL },
acfda38b75d0f0e899ef692fef01593bd56ed85eTimo Sirainen { '$', msg, NULL },
acfda38b75d0f0e899ef692fef01593bd56ed85eTimo Sirainen { '\0', NULL, NULL }
acfda38b75d0f0e899ef692fef01593bd56ed85eTimo Sirainen };
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen
acfda38b75d0f0e899ef692fef01593bd56ed85eTimo Sirainen str_truncate(str, 0);
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen if (var_expand(str, client->set->login_log_format, tab, &error) <= 0) {
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen i_error("Failed to expand login_log_format=%s: %s",
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen client->set->login_log_format, error);
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen expand_error_logged = TRUE;
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen }
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen return str_c(str);
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen}
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenvoid client_log(struct client *client, const char *msg)
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen{
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen T_BEGIN {
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen i_info("%s", client_get_log_str(client, msg));
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen } T_END;
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen}
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenvoid client_log_err(struct client *client, const char *msg)
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen{
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen T_BEGIN {
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen i_error("%s", client_get_log_str(client, msg));
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen } T_END;
1d4f710106fb498750456724628da6063e012e6dTimo Sirainen}
89795c6bbbc52bb382e88bc8617d22092223e9a5Timo Sirainen
b9c76fe9d9ca194816606342da1ddbd9be6bc8abTimo Sirainenvoid client_log_warn(struct client *client, const char *msg)
b9c76fe9d9ca194816606342da1ddbd9be6bc8abTimo Sirainen{
b9c76fe9d9ca194816606342da1ddbd9be6bc8abTimo Sirainen T_BEGIN {
b9c76fe9d9ca194816606342da1ddbd9be6bc8abTimo Sirainen i_warning("%s", client_get_log_str(client, msg));
b9c76fe9d9ca194816606342da1ddbd9be6bc8abTimo Sirainen } T_END;
b9c76fe9d9ca194816606342da1ddbd9be6bc8abTimo Sirainen}
b9c76fe9d9ca194816606342da1ddbd9be6bc8abTimo Sirainen
6a9e034441607c0c5a61858ff559af4615ac31caTimo Sirainenbool client_is_tls_enabled(struct client *client)
6a9e034441607c0c5a61858ff559af4615ac31caTimo Sirainen{
3e06f836ce9c97ad09c7cb4b5660c5787900c1c6Timo Sirainen return login_ssl_initialized && strcmp(client->ssl_set->ssl, "no") != 0;
6a9e034441607c0c5a61858ff559af4615ac31caTimo Sirainen}
6a9e034441607c0c5a61858ff559af4615ac31caTimo Sirainen
38318f5e82662615cd88e99e398efe4a630ce020Timo Sirainenconst char *client_get_extra_disconnect_reason(struct client *client)
38318f5e82662615cd88e99e398efe4a630ce020Timo Sirainen{
28dae6a0064e79f86da091625b0f2b92336a2a91Timo Sirainen unsigned int auth_secs = client->auth_first_started == 0 ? 0 :
28dae6a0064e79f86da091625b0f2b92336a2a91Timo Sirainen ioloop_time - client->auth_first_started;
28dae6a0064e79f86da091625b0f2b92336a2a91Timo Sirainen
434abef12f61881a5cfa28d27193d0854a9639a0Timo Sirainen if (client->set->auth_ssl_require_client_cert &&
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen client->ssl_iostream != NULL) {
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen if (ssl_iostream_has_broken_client_cert(client->ssl_iostream))
38318f5e82662615cd88e99e398efe4a630ce020Timo Sirainen return "(client sent an invalid cert)";
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen if (!ssl_iostream_has_valid_client_cert(client->ssl_iostream))
38318f5e82662615cd88e99e398efe4a630ce020Timo Sirainen return "(client didn't send a cert)";
38318f5e82662615cd88e99e398efe4a630ce020Timo Sirainen }
38318f5e82662615cd88e99e398efe4a630ce020Timo Sirainen
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen if (!client->notified_auth_ready)
b9c76fe9d9ca194816606342da1ddbd9be6bc8abTimo Sirainen return t_strdup_printf(
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen "(disconnected before auth was ready, waited %u secs)",
b9c76fe9d9ca194816606342da1ddbd9be6bc8abTimo Sirainen (unsigned int)(ioloop_time - client->created));
b9c76fe9d9ca194816606342da1ddbd9be6bc8abTimo Sirainen
28dae6a0064e79f86da091625b0f2b92336a2a91Timo Sirainen if (client->auth_attempts == 0) {
56af9dd10e7e6caeaca64395bad3f882b28ecdffTimo Sirainen if (!client->banner_sent) {
56af9dd10e7e6caeaca64395bad3f882b28ecdffTimo Sirainen /* disconnected by a plugin */
56af9dd10e7e6caeaca64395bad3f882b28ecdffTimo Sirainen return "";
56af9dd10e7e6caeaca64395bad3f882b28ecdffTimo Sirainen }
28dae6a0064e79f86da091625b0f2b92336a2a91Timo Sirainen return t_strdup_printf("(no auth attempts in %u secs)",
28dae6a0064e79f86da091625b0f2b92336a2a91Timo Sirainen (unsigned int)(ioloop_time - client->created));
28dae6a0064e79f86da091625b0f2b92336a2a91Timo Sirainen }
38318f5e82662615cd88e99e398efe4a630ce020Timo Sirainen
38318f5e82662615cd88e99e398efe4a630ce020Timo Sirainen /* some auth attempts without SSL/TLS */
b4b87fa19d26aadb2ea9e8a9ae7af6cfdaab4cfbTimo Sirainen if (client->set->auth_ssl_require_client_cert &&
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen client->ssl_iostream == NULL)
38318f5e82662615cd88e99e398efe4a630ce020Timo Sirainen return "(cert required, client didn't start TLS)";
04eb0abcf8f8b0c014499b5c5bae89484553613fStephan Bosch
6998ca95b4947c90647ac5d4794ebd6311acada2Timo Sirainen if (client->auth_waiting && client->auth_attempts == 1) {
6998ca95b4947c90647ac5d4794ebd6311acada2Timo Sirainen return t_strdup_printf("(client didn't finish SASL auth, "
6998ca95b4947c90647ac5d4794ebd6311acada2Timo Sirainen "waited %u secs)", auth_secs);
6998ca95b4947c90647ac5d4794ebd6311acada2Timo Sirainen }
28dae6a0064e79f86da091625b0f2b92336a2a91Timo Sirainen if (client->auth_request != NULL && client->auth_attempts == 1) {
28dae6a0064e79f86da091625b0f2b92336a2a91Timo Sirainen return t_strdup_printf("(disconnected while authenticating, "
28dae6a0064e79f86da091625b0f2b92336a2a91Timo Sirainen "waited %u secs)", auth_secs);
28dae6a0064e79f86da091625b0f2b92336a2a91Timo Sirainen }
28dae6a0064e79f86da091625b0f2b92336a2a91Timo Sirainen if (client->authenticating && client->auth_attempts == 1) {
28dae6a0064e79f86da091625b0f2b92336a2a91Timo Sirainen return t_strdup_printf("(disconnected while finishing login, "
28dae6a0064e79f86da091625b0f2b92336a2a91Timo Sirainen "waited %u secs)", auth_secs);
28dae6a0064e79f86da091625b0f2b92336a2a91Timo Sirainen }
3ffb7fd86484c474b42f3f1e981ab0f7168b5df9Timo Sirainen if (client->auth_try_aborted && client->auth_attempts == 1)
3ffb7fd86484c474b42f3f1e981ab0f7168b5df9Timo Sirainen return "(aborted authentication)";
7c849dbc7be089175c1a83a84ee7249ed695810dTimo Sirainen if (client->auth_process_comm_fail)
7c849dbc7be089175c1a83a84ee7249ed695810dTimo Sirainen return "(auth process communication failure)";
38318f5e82662615cd88e99e398efe4a630ce020Timo Sirainen
80980955bb1bbcc1bd73623fe0912f334194ddd2Timo Sirainen if (client->proxy_auth_failed)
80980955bb1bbcc1bd73623fe0912f334194ddd2Timo Sirainen return "(proxy dest auth failed)";
843640f0ca224bb9999acb290bca5f76037ab984Timo Sirainen if (client->auth_successes > 0) {
3f878e1442c881e4c5a80661b391926bcdee6016Timo Sirainen return t_strdup_printf("(internal failure, %u successful auths)",
843640f0ca224bb9999acb290bca5f76037ab984Timo Sirainen client->auth_successes);
843640f0ca224bb9999acb290bca5f76037ab984Timo Sirainen }
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch switch (client->last_auth_fail) {
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch case CLIENT_AUTH_FAIL_CODE_AUTHZFAILED:
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch return t_strdup_printf(
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch "(authorization failed, %u attempts in %u secs)",
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch client->auth_attempts, auth_secs);
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch case CLIENT_AUTH_FAIL_CODE_TEMPFAIL:
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch return "(auth service reported temporary failure)";
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch case CLIENT_AUTH_FAIL_CODE_USER_DISABLED:
ca843e046e98b12f4730f4b87ee2e1a659c26e78Timo Sirainen return "(user disabled)";
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch case CLIENT_AUTH_FAIL_CODE_PASS_EXPIRED:
ca843e046e98b12f4730f4b87ee2e1a659c26e78Timo Sirainen return "(password expired)";
8ac6623677005256bf99ab33a2ed98c69c1d656cStephan Bosch case CLIENT_AUTH_FAIL_CODE_INVALID_BASE64:
8ac6623677005256bf99ab33a2ed98c69c1d656cStephan Bosch return "(sent invalid base64 in response)";
f32d0295c90ed810889504cdfa5e1a25a415f65fStephan Bosch case CLIENT_AUTH_FAIL_CODE_LOGIN_DISABLED:
f32d0295c90ed810889504cdfa5e1a25a415f65fStephan Bosch return "(login disabled)";
04eb0abcf8f8b0c014499b5c5bae89484553613fStephan Bosch case CLIENT_AUTH_FAIL_CODE_MECH_INVALID:
04eb0abcf8f8b0c014499b5c5bae89484553613fStephan Bosch return "(tried to use unsupported auth mechanism)";
04eb0abcf8f8b0c014499b5c5bae89484553613fStephan Bosch case CLIENT_AUTH_FAIL_CODE_MECH_SSL_REQUIRED:
04eb0abcf8f8b0c014499b5c5bae89484553613fStephan Bosch return "(tried to use disallowed plaintext auth)";
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch default:
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch break;
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch }
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch
28dae6a0064e79f86da091625b0f2b92336a2a91Timo Sirainen return t_strdup_printf("(auth failed, %u attempts in %u secs)",
28dae6a0064e79f86da091625b0f2b92336a2a91Timo Sirainen client->auth_attempts, auth_secs);
38318f5e82662615cd88e99e398efe4a630ce020Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainenvoid client_notify_disconnect(struct client *client,
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen enum client_disconnect_reason reason,
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen const char *text)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen if (!client->notified_disconnect) {
ab90f702ceedb7ba445a9a592be0b213b27cbafaStephan Bosch if (client->v.notify_disconnect != NULL)
ab90f702ceedb7ba445a9a592be0b213b27cbafaStephan Bosch client->v.notify_disconnect(client, reason, text);
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen client->notified_disconnect = TRUE;
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen }
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen}
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainenvoid client_notify_auth_ready(struct client *client)
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen{
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen if (!client->notified_auth_ready) {
ab90f702ceedb7ba445a9a592be0b213b27cbafaStephan Bosch if (client->v.notify_auth_ready != NULL)
ab90f702ceedb7ba445a9a592be0b213b27cbafaStephan Bosch client->v.notify_auth_ready(client);
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen client->notified_auth_ready = TRUE;
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen }
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen}
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainenvoid client_notify_status(struct client *client, bool bad, const char *text)
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen{
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen if (client->v.notify_status != NULL)
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen client->v.notify_status(client, bad, text);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
ae797f3368ebb86e7786ca25d7c9c703f672b9f5Timo Sirainenvoid client_common_send_raw_data(struct client *client,
ae797f3368ebb86e7786ca25d7c9c703f672b9f5Timo Sirainen const void *data, size_t size)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen ssize_t ret;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen ret = o_stream_send(client->output, data, size);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (ret < 0 || (size_t)ret != size) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* either disconnection or buffer full. in either case we want
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen this connection destroyed. however destroying it here might
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen break things if client is still tried to be accessed without
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen being referenced.. */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_stream_close(client->input);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
ae797f3368ebb86e7786ca25d7c9c703f672b9f5Timo Sirainenvoid client_send_raw_data(struct client *client, const void *data, size_t size)
ae797f3368ebb86e7786ca25d7c9c703f672b9f5Timo Sirainen{
21b21a19b55ebd8dd8f719d1839f6f667ebfffecTimo Sirainen client->v.send_raw_data(client, data, size);
ae797f3368ebb86e7786ca25d7c9c703f672b9f5Timo Sirainen}
ae797f3368ebb86e7786ca25d7c9c703f672b9f5Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenvoid client_send_raw(struct client *client, const char *data)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_send_raw_data(client, data, strlen(data));
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenbool client_read(struct client *client)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen switch (i_stream_read(client->input)) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen case -2:
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* buffer full */
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen client_notify_disconnect(client,
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen CLIENT_DISCONNECT_RESOURCE_CONSTRAINT,
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen "Input buffer full, aborting");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_destroy(client, "Disconnected: Input buffer full");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return FALSE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen case -1:
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* disconnected */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_destroy(client, "Disconnected");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return FALSE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen case 0:
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* nothing new read */
a074b1e4012665af44b198a05baa5e478220ec3fTimo Sirainen return i_stream_get_data_size(client->input) > 0;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen default:
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* something was read */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return TRUE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenvoid client_input(struct client *client)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
a1852ab4cf0a942a3fcf4ca5636a7932ebcc7970Stephan Bosch i_assert(client->v.input != NULL);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->v.input(client);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainenvoid client_common_init(void)
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen{
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen i_array_init(&module_hooks, 32);
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen}
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen
a7efba62b6235e5efc124cbf702ddeb547ca3665Timo Sirainenvoid client_destroy_fd_proxies(void)
a7efba62b6235e5efc124cbf702ddeb547ca3665Timo Sirainen{
a7efba62b6235e5efc124cbf702ddeb547ca3665Timo Sirainen while (client_fd_proxies != NULL) {
a7efba62b6235e5efc124cbf702ddeb547ca3665Timo Sirainen struct client *client = client_fd_proxies;
a7efba62b6235e5efc124cbf702ddeb547ca3665Timo Sirainen client_unref(&client);
a7efba62b6235e5efc124cbf702ddeb547ca3665Timo Sirainen }
0256180043b9f55b606b523b775e8b23b1b12f83Timo Sirainen i_assert(client_fd_proxies_count == 0);
a7efba62b6235e5efc124cbf702ddeb547ca3665Timo Sirainen}
a7efba62b6235e5efc124cbf702ddeb547ca3665Timo Sirainen
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainenvoid client_common_deinit(void)
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen{
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen array_free(&module_hooks);
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen}