client-common.c revision c7eb1ffb7c73cb5d9c1316bbecd02947441a40d4
5a580c3a38ced62d4bcc95b8ac7c4f2935b5d294Timo Sirainen/* Copyright (c) 2002-2013 Dovecot authors, see the included COPYING file */
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenstruct client *clients = NULL, *last_client = NULL;
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainenstatic unsigned int clients_count = 0;
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainenstatic void client_idle_disconnect_timeout(struct client *client)
9fd2181788a61500641c66aec0f8c746b19bf830Timo Sirainen unsigned int secs;
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainen user_reason = "Timeout while finishing login.";
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen "Timeout while finishing login (waited %u secs)", secs);
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen "Disconnected for inactivity during authentication.";
a8d47e2427558d5011dfc75694b704760c1ef8baTimo Sirainen "Disconnected: Inactivity during authentication";
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen user_reason = "Timeout while finishing login.";
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen "proxy: Logging in to %s:%u timed out "
abc79eec93e58e0152cd1d483f37be66c26811b9Timo Sirainen "(state=%u, duration=%us)",
d9076f5939edf5d20a261494b1a861dcbb0d32e2Timo Sirainen client_notify_disconnect(client, CLIENT_DISCONNECT_TIMEOUT, user_reason);
a8d47e2427558d5011dfc75694b704760c1ef8baTimo Sirainenstatic void client_open_streams(struct client *client)
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen i_stream_create_fd(client->fd, LOGIN_MAX_INBUF_SIZE, FALSE);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen o_stream_create_fd(client->fd, LOGIN_MAX_OUTBUF_SIZE, FALSE);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen o_stream_set_no_error_handling(client->output, TRUE);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen if (iostream_rawlog_create(login_rawlog_dir, &client->input,
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainenstatic bool client_is_trusted(struct client *client)
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen const char *const *net;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen unsigned int bits;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen if (client->set->login_trusted_networks == NULL)
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen net = t_strsplit_spaces(client->set->login_trusted_networks, ", ");
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen if (net_parse_range(*net, &net_ip, &bits) < 0) {
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen if (net_is_in_network(&client->ip, &net_ip, bits))
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen const struct master_service_ssl_settings *ssl_set,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen const struct ip_addr *local_ip, const struct ip_addr *remote_ip)
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen client = login_binary->client_vfuncs->alloc(pool);
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen client->v.auth_send_challenge = client_auth_send_challenge;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen client->v.auth_parse_response = client_auth_parse_response;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen client->real_local_ip = client->local_ip = *local_ip;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen client->real_remote_ip = client->ip = *remote_ip;
e51cfb5506de764499cb5b81a098b23cf46f90f1Timo Sirainenvoid client_destroy(struct client *client, const char *reason)
e51cfb5506de764499cb5b81a098b23cf46f90f1Timo Sirainen if (!client->login_success && reason != NULL) {
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen client_get_extra_disconnect_reason(client), NULL);
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen master_auth_request_abort(master_auth, client->master_tag);
f9142439f2b5e86065af7420e80fe52835227dc8Timo Sirainen dsasl_client_free(&client->proxy_sasl_client);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (client_unref(&client) && initial_service_count == 1) {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen /* as soon as this connection is done with proxying
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen (or whatever), the process will die. there's no need for
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen authentication anymore, so close the connection.
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen do this only with initial service_count=1, in case there
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen are other clients with pending authentications */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen auth_client_disconnect(auth_client, "unnecessary connection");
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenvoid client_destroy_success(struct client *client, const char *reason)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenvoid client_destroy_internal_failure(struct client *client)
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen client_notify_disconnect(client, CLIENT_DISCONNECT_INTERNAL_ERROR,
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen "Internal login failure. "
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen "Refer to server log for more information.");
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainen "Internal login failure (pid=%s id=%u)",
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainen master_service_client_connection_destroyed(master_service);
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen /* we have no clients */
5736aef6d0abe6796e57c2eda68f5c25db677918Timo Sirainen /* destroy the last client that hasn't successfully authenticated yet.
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen this is usually the last client, but don't kill it if it's just
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen waiting for master to finish its job. */
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen for (client = last_client; client != NULL; client = client->prev) {
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen client_notify_disconnect(client, CLIENT_DISCONNECT_RESOURCE_CONSTRAINT,
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen "Connection queue full");
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen client_destroy(client, "Disconnected: Connection queue full");
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainenvoid clients_destroy_all_reason(const char *reason)
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen for (client = clients; client != NULL; client = next) {
117a55d4260651770705ecb96f68be2dab03b99bTimo Sirainen clients_destroy_all_reason("Disconnected: Shutting down");
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainenstatic void client_start_tls(struct client *client)
117a55d4260651770705ecb96f68be2dab03b99bTimo Sirainen if (!client_unref(&client) || client->destroyed)
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen fd_ssl = ssl_proxy_alloc(client->fd, &client->ip, client->pool,
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen "TLS initialization failed.");
dd7cbb32412c2f4d2d223af66672535bc1237246Timo Sirainen "Disconnected: TLS initialization failed.");
dd7cbb32412c2f4d2d223af66672535bc1237246Timo Sirainen ssl_proxy_set_client(client->ssl_proxy, client);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen client->io = io_add(client->fd, IO_READ, client_input, client);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic int client_output_starttls(struct client *client)
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen if ((ret = o_stream_flush(client->output)) < 0) {
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen o_stream_unset_flush_callback(client->output);
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainenvoid client_cmd_starttls(struct client *client)
cb17980a661554ebb3fd099c77e92a5be4d304ecTimo Sirainen client->v.notify_starttls(client, FALSE, "TLS is already active.");
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainen client->v.notify_starttls(client, FALSE, "TLS support isn't enabled.");
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainen /* remove input handler, SSL proxy gives us a new fd. we also have to
57f5683fd9dc9bc79816c418bb30fdbc33b68a8cTimo Sirainen remove it in case we have to wait for buffer to be flushed */
55a14bce15b9f44441b5f56616d73651a294d770Timo Sirainen client->v.notify_starttls(client, TRUE, "Begin TLS negotiation now.");
b16ee3cbbcd18cb86f2f73b5cc163ebfb995ffafTimo Sirainen /* uncork the old fd */
55a14bce15b9f44441b5f56616d73651a294d770Timo Sirainen /* the buffer has to be flushed */
b16ee3cbbcd18cb86f2f73b5cc163ebfb995ffafTimo Sirainen o_stream_set_flush_pending(client->output, TRUE);
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainenunsigned int clients_get_count(void)
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainenconst char *client_get_session_id(struct client *client)
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainen unsigned int i;
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainen buf = buffer_create_dynamic(pool_datastack_create(), 24);
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainen base64_buf = buffer_create_dynamic(pool_datastack_create(), 24*2);
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainen timestamp = tv.tv_usec + (long long)tv.tv_sec * 1000ULL*1000ULL;
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainen /* add lowest 48 bits of the timestamp. this gives us a bit less than
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainen 9 years until it wraps */
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainen buffer_append_c(buf, (timestamp >> i) & 0xff);
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainen buffer_append_c(buf, client->remote_port & 0xff);
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainen buffer_append_c(buf, (client->remote_port >> 16) & 0xff);
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainen buffer_append(buf, &client->ip.u.ip6, sizeof(client->ip.u.ip6));
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen buffer_append(buf, &client->ip.u.ip4, sizeof(client->ip.u.ip4));
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen base64_encode(buf->data, buf->used, base64_buf);
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen client->session_id = p_strdup(client->pool, str_c(base64_buf));
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainenstatic struct var_expand_table login_var_expand_empty_tab[] = {
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainenstatic const struct var_expand_table *
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen unsigned int i;
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen tab = t_malloc(sizeof(login_var_expand_empty_tab));
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen tab[1].value = t_strcut(client->virtual_user, '@');
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen tab[2].value = strchr(client->virtual_user, '@');
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen for (i = 0; i < 3; i++)
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen tab[i].value = str_sanitize(tab[i].value, 80);
const char *ssl_state =
const char *ssl_error =
return tab;
char key;
str++;
return TRUE;
return FALSE;
unsigned int pos;
if (have_username_key(*e)) {
T_BEGIN {
} T_END;
T_BEGIN {
} T_END;
T_BEGIN {
} T_END;
return t_strdup_printf(
const char *text)
return FALSE;
return FALSE;
return TRUE;
return TRUE;