client-common.c revision 12c6ef6f1268ed4d5b63709bb4215c481b4f078c
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (c) 2002-2012 Dovecot authors, see the included COPYING file */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "login-common.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "hostpid.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "llist.h"
5d60e31c7b701b606067a20bc88dcc8a6de7bbd6Timo Sirainen#include "istream.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "ostream.h"
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen#include "iostream-rawlog.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "process-title.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "str.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "str-sanitize.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "safe-memset.h"
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen#include "var-expand.h"
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen#include "master-interface.h"
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen#include "master-service.h"
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen#include "master-auth.h"
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen#include "auth-client.h"
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen#include "login-proxy.h"
daa7e7459749ae8f82cd3eed9c44522d81c609a3Timo Sirainen#include "ssl-proxy.h"
bbadd5331f534017cf62d5183003b3d9fdad079eTimo Sirainen#include "client-common.h"
373492be949e159fda651807b3acda2c5c077027Timo Sirainen
72f5f2c5c6905b5d3f389b424313e2c450dfad96Timo Sirainen#include <stdlib.h>
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainenstruct client *clients = NULL, *last_client = NULL;
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainenstatic unsigned int clients_count = 0;
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainenstatic void client_idle_disconnect_timeout(struct client *client)
373492be949e159fda651807b3acda2c5c077027Timo Sirainen{
bbadd5331f534017cf62d5183003b3d9fdad079eTimo Sirainen client_notify_disconnect(client, CLIENT_DISCONNECT_TIMEOUT,
bbadd5331f534017cf62d5183003b3d9fdad079eTimo Sirainen "Disconnected for inactivity.");
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen client_destroy(client, "Disconnected: Inactivity");
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen}
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainenstatic void client_open_streams(struct client *client)
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen{
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen client->input =
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen i_stream_create_fd(client->fd, LOGIN_MAX_INBUF_SIZE, FALSE);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen client->output =
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen o_stream_create_fd(client->fd, LOGIN_MAX_OUTBUF_SIZE, FALSE);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen if (login_rawlog_dir != NULL) {
635df5b4cbcd7b24c825e01d9dd66d3a4274c4c7Timo Sirainen if (iostream_rawlog_create(login_rawlog_dir, &client->input,
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen &client->output) < 0)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen login_rawlog_dir = NULL;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen }
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen}
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainenstatic bool client_is_trusted(struct client *client)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen{
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen const char *const *net;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen struct ip_addr net_ip;
51fb710488efa419a2964335c30451c62b9633b1Timo Sirainen unsigned int bits;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
93a7d1ee4b518b5c85f9721dc6539e4dab6aae00Timo Sirainen if (client->set->login_trusted_networks == NULL)
f7f25f9e1a38678d0e97d2e609beac16285fac6bTimo Sirainen return FALSE;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen net = t_strsplit_spaces(client->set->login_trusted_networks, ", ");
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen for (; *net != NULL; net++) {
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen if (net_parse_range(*net, &net_ip, &bits) < 0) {
35fcdde46a71ac151c2518d48c841019f1181bb2Timo Sirainen i_error("login_trusted_networks: "
35fcdde46a71ac151c2518d48c841019f1181bb2Timo Sirainen "Invalid network '%s'", *net);
35fcdde46a71ac151c2518d48c841019f1181bb2Timo Sirainen break;
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen }
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen if (net_is_in_network(&client->ip, &net_ip, bits))
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen return TRUE;
635df5b4cbcd7b24c825e01d9dd66d3a4274c4c7Timo Sirainen }
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen return FALSE;
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen}
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainenstruct client *
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainenclient_create(int fd, bool ssl, pool_t pool,
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen const struct login_settings *set, void **other_sets,
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen const struct ip_addr *local_ip, const struct ip_addr *remote_ip)
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen{
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen struct client *client;
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen i_assert(fd != -1);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen client = login_binary->client_vfuncs->alloc(pool);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen client->v = *login_binary->client_vfuncs;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen if (client->v.auth_send_challenge == NULL)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen client->v.auth_send_challenge = client_auth_send_challenge;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen if (client->v.auth_parse_response == NULL)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen client->v.auth_parse_response = client_auth_parse_response;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen client->created = ioloop_time;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen client->refcount = 1;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen client->pool = pool;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen client->set = set;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen client->local_ip = *local_ip;
ba8498efbf886ca8b69fdb20c0ba2f5dba9416e3Timo Sirainen client->ip = *remote_ip;
93a7d1ee4b518b5c85f9721dc6539e4dab6aae00Timo Sirainen client->fd = fd;
f7f25f9e1a38678d0e97d2e609beac16285fac6bTimo Sirainen client->tls = ssl;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen client->trusted = client_is_trusted(client);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen client->secured = ssl || client->trusted ||
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen net_ip_compare(remote_ip, local_ip);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen if (last_client == NULL)
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen last_client = client;
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen DLLIST_PREPEND(&clients, client);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen clients_count++;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen client->to_disconnect =
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen timeout_add(CLIENT_LOGIN_TIMEOUT_MSECS,
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen client_idle_disconnect_timeout, client);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen client_open_streams(client);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen client->v.create(client, other_sets);
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (auth_client_is_connected(auth_client))
380dbb60ae291cbe39d1f710284562ca9167150bTimo Sirainen client_notify_auth_ready(client);
380dbb60ae291cbe39d1f710284562ca9167150bTimo Sirainen else
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen client_set_auth_waiting(client);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen login_refresh_proctitle();
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen return client;
1b823b2b7790a1e1b7974fcf11a4c48a28e70f37Timo Sirainen}
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainenvoid client_destroy(struct client *client, const char *reason)
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen{
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen if (client->destroyed)
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen return;
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen client->destroyed = TRUE;
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen if (!client->login_success && reason != NULL) {
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen reason = t_strconcat(reason, " ",
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen client_get_extra_disconnect_reason(client), NULL);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen }
1b823b2b7790a1e1b7974fcf11a4c48a28e70f37Timo Sirainen if (reason != NULL)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen client_log(client, reason);
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen if (last_client == client)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen last_client = client->prev;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen DLLIST_REMOVE(&clients, client);
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen if (client->input != NULL)
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen i_stream_close(client->input);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (client->output != NULL)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen o_stream_close(client->output);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (client->master_tag != 0) {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen i_assert(client->auth_request == NULL);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen i_assert(client->authenticating);
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen i_assert(client->refcount > 1);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen client->authenticating = FALSE;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen master_auth_request_abort(master_auth, client->master_tag);
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen client->refcount--;
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen } else if (client->auth_request != NULL) {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen i_assert(client->authenticating);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen sasl_server_auth_abort(client);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen } else {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen i_assert(!client->authenticating);
1b823b2b7790a1e1b7974fcf11a4c48a28e70f37Timo Sirainen }
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen if (client->io != NULL)
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen io_remove(&client->io);
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen if (client->to_disconnect != NULL)
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen timeout_remove(&client->to_disconnect);
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen if (client->to_auth_waiting != NULL)
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen timeout_remove(&client->to_auth_waiting);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen if (client->auth_response != NULL)
1b823b2b7790a1e1b7974fcf11a4c48a28e70f37Timo Sirainen str_free(&client->auth_response);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen if (client->fd != -1) {
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen net_disconnect(client->fd);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen client->fd = -1;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen }
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen if (client->proxy_password != NULL) {
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen safe_memset(client->proxy_password, 0,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen strlen(client->proxy_password));
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen i_free_and_null(client->proxy_password);
57d2429fae575e96ca276355af675deb66b76d00Timo Sirainen }
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
401b0787fff2dc986a5321ddb32acb1947ff66b0Timo Sirainen if (client->login_proxy != NULL)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen login_proxy_free(&client->login_proxy);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (client->ssl_proxy != NULL)
57d2429fae575e96ca276355af675deb66b76d00Timo Sirainen ssl_proxy_free(&client->ssl_proxy);
401b0787fff2dc986a5321ddb32acb1947ff66b0Timo Sirainen client->v.destroy(client);
401b0787fff2dc986a5321ddb32acb1947ff66b0Timo 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.
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo 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 }
61618d4c58080570f689614fec204ae14e90cef2Timo Sirainen login_client_destroyed();
50e20db49f29917fe9adcf1b56b11badf28bd0e4Timo Sirainen login_refresh_proctitle();
50e20db49f29917fe9adcf1b56b11badf28bd0e4Timo Sirainen}
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenvoid client_destroy_success(struct client *client, const char *reason)
a64adf62fa33f2463a86f990217b0c9078531a40Timo 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)
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen{
50e20db49f29917fe9adcf1b56b11badf28bd0e4Timo Sirainen client_notify_disconnect(client, CLIENT_DISCONNECT_INTERNAL_ERROR,
a7f5035eebbd138a5436a2eb2ce1fa5fd3d269fbTimo Sirainen "Internal login failure. "
a7f5035eebbd138a5436a2eb2ce1fa5fd3d269fbTimo Sirainen "Refer to server log for more information.");
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen client_destroy(client, t_strdup_printf(
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen "Internal login failure (pid=%s id=%u)",
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen my_pid, client->master_auth_id));
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen}
c6f894e1522f7b0b6068c228900914073c145175Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenvoid client_ref(struct client *client)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen{
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen client->refcount++;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen}
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenbool client_unref(struct client **_client)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen{
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen struct client *client = *_client;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
1da01eaa962be13cee75771064e2256b1a82d90aTimo Sirainen i_assert(client->refcount > 0);
401b0787fff2dc986a5321ddb32acb1947ff66b0Timo Sirainen if (--client->refcount > 0)
401b0787fff2dc986a5321ddb32acb1947ff66b0Timo Sirainen return TRUE;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen *_client = NULL;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen i_assert(client->destroyed);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen i_assert(client->ssl_proxy == NULL);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen i_assert(client->login_proxy == NULL);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen if (client->input != NULL)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen i_stream_unref(&client->input);
f2df3069766c747cbf020fea5d3a4261949064b0Timo Sirainen if (client->output != NULL)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen o_stream_unref(&client->output);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
062ea54b7775d0c92ed67b9b1f4d93fa8ec80c84Timo Sirainen i_free(client->proxy_user);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen i_free(client->proxy_master_user);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen i_free(client->virtual_user);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen i_free(client->auth_mech_name);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen pool_unref(&client->pool);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen i_assert(clients_count > 0);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen clients_count--;
a7f5035eebbd138a5436a2eb2ce1fa5fd3d269fbTimo Sirainen
a7f5035eebbd138a5436a2eb2ce1fa5fd3d269fbTimo Sirainen master_service_client_connection_destroyed(master_service);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen login_refresh_proctitle();
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen return FALSE;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen}
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
c6f894e1522f7b0b6068c228900914073c145175Timo Sirainenvoid client_destroy_oldest(void)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen{
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen struct client *client;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen if (last_client == NULL) {
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen /* we have no clients */
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen return;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen }
401b0787fff2dc986a5321ddb32acb1947ff66b0Timo Sirainen
401b0787fff2dc986a5321ddb32acb1947ff66b0Timo Sirainen /* destroy the last client that hasn't successfully authenticated yet.
1da01eaa962be13cee75771064e2256b1a82d90aTimo Sirainen this is usually the last client, but don't kill it if it's just
401b0787fff2dc986a5321ddb32acb1947ff66b0Timo Sirainen waiting for master to finish its job. */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen for (client = last_client; client != NULL; client = client->prev) {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (client->master_tag == 0)
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen break;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen }
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen if (client == NULL)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen client = last_client;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen client_notify_disconnect(client, CLIENT_DISCONNECT_RESOURCE_CONSTRAINT,
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen "Connection queue full");
383d0e8c24451468d6bea17e4b55d74de744abe6Timo Sirainen client_destroy(client, "Disconnected: Connection queue full");
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen}
383d0e8c24451468d6bea17e4b55d74de744abe6Timo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainenvoid clients_destroy_all(void)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen{
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen struct client *client, *next;
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen for (client = clients; client != NULL; client = next) {
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen next = client->next;
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen client_notify_disconnect(client,
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen CLIENT_DISCONNECT_SYSTEM_SHUTDOWN, "Shutting down.");
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen client_destroy(client, "Disconnected: Shutting down");
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen }
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen}
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainenstatic void client_start_tls(struct client *client)
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen{
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen int fd_ssl;
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen client_ref(client);
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen if (!client_unref(&client) || client->destroyed)
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen return;
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen fd_ssl = ssl_proxy_alloc(client->fd, &client->ip,
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen client->set, &client->ssl_proxy);
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen if (fd_ssl == -1) {
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen client_notify_disconnect(client,
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen CLIENT_DISCONNECT_INTERNAL_ERROR,
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen "TLS initialization failed.");
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen client_destroy(client,
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen "Disconnected: TLS initialization failed.");
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen return;
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen }
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen ssl_proxy_set_client(client->ssl_proxy, client);
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen ssl_proxy_start(client->ssl_proxy);
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen client->starttls = TRUE;
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen client->tls = TRUE;
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen client->secured = TRUE;
4fc74bba3548987b7e8597491cd9fafc1f701be6Timo Sirainen login_refresh_proctitle();
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen client->fd = fd_ssl;
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen client->io = io_add(client->fd, IO_READ, client_input, client);
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen i_stream_unref(&client->input);
15f526e5ac611b4532568d131fcd0abf664abe41Timo Sirainen o_stream_unref(&client->output);
15f526e5ac611b4532568d131fcd0abf664abe41Timo Sirainen client_open_streams(client);
15f526e5ac611b4532568d131fcd0abf664abe41Timo Sirainen
15f526e5ac611b4532568d131fcd0abf664abe41Timo Sirainen client->v.starttls(client);
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen}
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainenstatic int client_output_starttls(struct client *client)
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen{
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen int ret;
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen
6bd263caf006edc75205f446fa0283c6f364941bTimo Sirainen if ((ret = o_stream_flush(client->output)) < 0) {
4fc74bba3548987b7e8597491cd9fafc1f701be6Timo Sirainen client_destroy(client, "Disconnected");
4fc74bba3548987b7e8597491cd9fafc1f701be6Timo Sirainen return 1;
4fc74bba3548987b7e8597491cd9fafc1f701be6Timo Sirainen }
4fc74bba3548987b7e8597491cd9fafc1f701be6Timo Sirainen
4fc74bba3548987b7e8597491cd9fafc1f701be6Timo Sirainen if (ret > 0) {
4fc74bba3548987b7e8597491cd9fafc1f701be6Timo Sirainen o_stream_unset_flush_callback(client->output);
4fc74bba3548987b7e8597491cd9fafc1f701be6Timo Sirainen client_start_tls(client);
4fc74bba3548987b7e8597491cd9fafc1f701be6Timo Sirainen }
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen return 1;
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen}
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainenvoid client_cmd_starttls(struct client *client)
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen{
0f62889d833767acf9c2ad010c3269806b4cfae3Timo Sirainen if (client->tls) {
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen client->v.notify_starttls(client, FALSE, "TLS is already active.");
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen return;
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen }
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen if (!ssl_initialized) {
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen client->v.notify_starttls(client, FALSE, "TLS support isn't enabled.");
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen return;
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen }
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen /* remove input handler, SSL proxy gives us a new fd. we also have to
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen remove it in case we have to wait for buffer to be flushed */
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen if (client->io != NULL)
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen io_remove(&client->io);
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen client->v.notify_starttls(client, TRUE, "Begin TLS negotiation now.");
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen /* uncork the old fd */
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen o_stream_uncork(client->output);
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen if (o_stream_flush(client->output) <= 0) {
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen /* the buffer has to be flushed */
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen o_stream_set_flush_pending(client->output, TRUE);
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen o_stream_set_flush_callback(client->output,
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen client_output_starttls, client);
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen } else {
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen client_start_tls(client);
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen }
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen}
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainenunsigned int clients_get_count(void)
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen{
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen return clients_count;
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen}
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainenstatic const struct var_expand_table *
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainenget_var_expand_table(struct client *client)
272aca0a772140d3a45a425a3fd67854ae2ccec2Timo Sirainen{
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen static struct var_expand_table static_tab[] = {
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen { 'u', NULL, "user" },
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen { 'n', NULL, "username" },
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen { 'd', NULL, "domain" },
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen { 's', NULL, "service" },
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen { 'h', NULL, "home" },
1d22eaac93de41319918a1fc6de42bb302e25c1aTimo Sirainen { 'l', NULL, "lip" },
1d22eaac93de41319918a1fc6de42bb302e25c1aTimo Sirainen { 'r', NULL, "rip" },
5d60e31c7b701b606067a20bc88dcc8a6de7bbd6Timo Sirainen { 'p', NULL, "pid" },
5d60e31c7b701b606067a20bc88dcc8a6de7bbd6Timo Sirainen { 'm', NULL, "mech" },
5d60e31c7b701b606067a20bc88dcc8a6de7bbd6Timo Sirainen { 'a', NULL, "lport" },
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen { 'b', NULL, "rport" },
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen { 'c', NULL, "secured" },
2024157e8de36edd31f5fd72f5ea7364a0955fa7Timo Sirainen { 'k', NULL, "ssl_security" },
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen { 'e', NULL, "mail_pid" },
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen { '\0', NULL, NULL }
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen };
5d60e31c7b701b606067a20bc88dcc8a6de7bbd6Timo Sirainen struct var_expand_table *tab;
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen unsigned int i;
b215a8a123623782554a83f3025ef4e771bd8f01Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen tab = t_malloc(sizeof(static_tab));
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen memcpy(tab, static_tab, sizeof(static_tab));
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen if (client->virtual_user != NULL) {
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen tab[0].value = client->virtual_user;
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen tab[1].value = t_strcut(client->virtual_user, '@');
5d60e31c7b701b606067a20bc88dcc8a6de7bbd6Timo Sirainen tab[2].value = strchr(client->virtual_user, '@');
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (tab[2].value != NULL) tab[2].value++;
b215a8a123623782554a83f3025ef4e771bd8f01Timo Sirainen
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen for (i = 0; i < 3; i++)
5d60e31c7b701b606067a20bc88dcc8a6de7bbd6Timo Sirainen tab[i].value = str_sanitize(tab[i].value, 80);
5d60e31c7b701b606067a20bc88dcc8a6de7bbd6Timo Sirainen }
5d60e31c7b701b606067a20bc88dcc8a6de7bbd6Timo Sirainen tab[3].value = login_binary->protocol;
5d60e31c7b701b606067a20bc88dcc8a6de7bbd6Timo Sirainen tab[4].value = getenv("HOME");
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen tab[5].value = net_ip2addr(&client->local_ip);
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen tab[6].value = net_ip2addr(&client->ip);
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen tab[7].value = my_pid;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen 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);
return tab;
}
static bool have_key(const struct var_expand_table *table, const char *str)
{
char key;
unsigned int i;
key = var_get_key(str);
for (i = 0; table[i].key != '\0'; i++) {
if (table[i].key == key) {
if (table[i].value == NULL)
return FALSE;
if (table[i].value[0] != '\0')
return TRUE;
/* "" key - hide except in username */
return key == 'u' || key == 'n';
}
}
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;
const char *p;
char *const *e;
string_t *str;
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);
for (e = client->set->log_format_elements_split; *e != NULL; e++) {
for (p = *e; *p != '\0'; p++) {
if (*p != '%' || p[1] == '\0')
continue;
p++;
if (have_key(var_expand_table, p)) {
if (str_len(str) > 0)
str_append(str, ", ");
var_expand(str, *e, var_expand_table);
break;
}
}
}
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;
}
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 disabled 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 succesful auths)",
client->auth_successes);
}
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) {
client->v.notify_disconnect(client, reason, text);
client->notified_disconnect = TRUE;
}
}
void client_notify_auth_ready(struct client *client)
{
if (!client->notified_auth_ready) {
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);
}