client-common.c revision 0256180043b9f55b606b523b775e8b23b1b12f83
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* Copyright (c) 2002-2017 Dovecot authors, see the included COPYING file */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic unsigned int clients_count = 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic struct client *client_fd_proxies = NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic unsigned int client_fd_proxies_count = 0;
ee246b46953e4b94b2f22e093373674fa9155500Timo Sirainenstatic ARRAY(struct login_client_module_hooks) module_hooks = ARRAY_INIT;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainenvoid login_client_hooks_add(struct module *module,
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainenvoid login_client_hooks_remove(const struct login_client_hooks *hooks)
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen const struct login_client_module_hooks *module_hook;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen idx = array_foreach_idx(&module_hooks, module_hook);
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainenstatic void hook_login_client_allocated(struct client *client)
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen const struct login_client_module_hooks *module_hook;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen ctx = hook_build_init((void *)&client->v, sizeof(client->v));
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen if (module_hook->hooks->client_allocated != NULL) T_BEGIN {
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainenstatic void client_idle_disconnect_timeout(struct client *client)
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen unsigned int secs;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen user_reason = "Timeout while finishing login.";
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen "Timeout while finishing login (waited %u secs)", secs);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen "Disconnected for inactivity during authentication.";
5626ae5e3316eced244adb6485c0927f1c7fdc41Timo Sirainen "Disconnected: Inactivity during authentication";
5626ae5e3316eced244adb6485c0927f1c7fdc41Timo Sirainen user_reason = "Timeout while finishing login.";
5626ae5e3316eced244adb6485c0927f1c7fdc41Timo Sirainen "proxy: Logging in to %s:%u timed out "
5626ae5e3316eced244adb6485c0927f1c7fdc41Timo Sirainen "(state=%s, duration=%us)",
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen client_notify_disconnect(client, CLIENT_DISCONNECT_TIMEOUT, user_reason);
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainenstatic void client_open_streams(struct client *client)
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen client->input = i_stream_create_fd(client->fd, LOGIN_MAX_INBUF_SIZE);
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen client->output = o_stream_create_fd(client->fd, LOGIN_MAX_OUTBUF_SIZE);
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen o_stream_set_no_error_handling(client->output, TRUE);
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen if (iostream_rawlog_create(login_rawlog_dir, &client->input,
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainenstatic bool client_is_trusted(struct client *client)
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen const char *const *net;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen unsigned int bits;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen if (client->set->login_trusted_networks == NULL)
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen net = t_strsplit_spaces(client->set->login_trusted_networks, ", ");
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen if (net_parse_range(*net, &net_ip, &bits) < 0) {
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen if (net_is_in_network(&client->ip, &net_ip, bits))
7c95b03620a03a43dd72d39608cea5fc77393ad6Timo Sirainen const struct master_service_ssl_settings *ssl_set)
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen client = login_binary->client_vfuncs->alloc(pool);
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen client->v.auth_send_challenge = client_auth_send_challenge;
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen client->v.auth_parse_response = client_auth_parse_response;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen client->preproxy_pool = pool_alloconly_create(MEMPOOL_GROWING"preproxy pool", 256);
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen p_array_init(&client->module_contexts, client->pool, 5);
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen client->real_local_port = conn->real_local_port;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen client->real_remote_ip = conn->real_remote_ip;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen client->real_remote_port = conn->real_remote_port;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen client->listener_name = p_strdup(client->pool, conn->name);
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen client->secured = conn->proxy.ssl || client->trusted;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen client->client_cert_common_name = conn->proxy.cert_common_name;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen net_ip_compare(&conn->real_remote_ip, &conn->real_local_ip);
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainenvoid client_init(struct client *client, void **other_sets)
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainenvoid client_destroy(struct client *client, const char *reason)
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen !client->no_extra_disconnect_reason && reason != NULL) {
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen reason = t_strconcat(reason, " ", extra_reason, NULL);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen iostream_proxy_unref(&client->iostream_fd_proxy);
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen /* Login was successful. We may now be proxying the connection,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen so don't disconnect the client until client_unref(). */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen master_auth_request_abort(master_auth, client->master_tag);
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen dsasl_client_free(&client->proxy_sasl_client);
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen if (client_unref(&client) && initial_service_count == 1) {
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen /* as soon as this connection is done with proxying
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen (or whatever), the process will die. there's no need for
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen authentication anymore, so close the connection.
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen do this only with initial service_count=1, in case there
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen are other clients with pending authentications */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen auth_client_disconnect(auth_client, "unnecessary connection");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid client_destroy_success(struct client *client, const char *reason)
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen iostream_proxy_unref(&client->iostream_fd_proxy);
3c24d47ad5ff02ea00684233bef314ef2eefda4aTimo Sirainen master_service_client_connection_destroyed(master_service);
4c1827d5d718d6f610df3209a2eb95a6591698afTimo Sirainenvoid client_common_default_free(struct client *client ATTR_UNUSED)
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen /* we have no clients */
91b5eae18db48ebb70eee5407a7ab52bf798ee12Timo Sirainen /* destroy the last client that hasn't successfully authenticated yet.
91b5eae18db48ebb70eee5407a7ab52bf798ee12Timo Sirainen this is usually the last client, but don't kill it if it's just
91b5eae18db48ebb70eee5407a7ab52bf798ee12Timo Sirainen waiting for master to finish its job. */
91b5eae18db48ebb70eee5407a7ab52bf798ee12Timo Sirainen for (client = last_client; client != NULL; client = client->prev) {
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen client_notify_disconnect(client, CLIENT_DISCONNECT_RESOURCE_CONSTRAINT,
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen "Connection queue full");
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen client_destroy(client, "Disconnected: Connection queue full");
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainenvoid clients_destroy_all_reason(const char *reason)
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen for (client = clients; client != NULL; client = next) {
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen clients_destroy_all_reason("Disconnected: Shutting down");
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen fd_ssl = ssl_proxy_alloc(client->fd, &client->ip, client->pool,
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen ssl_proxy_set_client(client->ssl_proxy, client);
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainenstatic void client_start_tls(struct client *client)
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen "TLS initialization failed.");
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen "Disconnected: TLS initialization failed.");
4c1827d5d718d6f610df3209a2eb95a6591698afTimo Sirainen client->io = io_add(client->fd, IO_READ, client_input, client);
91b5eae18db48ebb70eee5407a7ab52bf798ee12Timo Sirainenstatic int client_output_starttls(struct client *client)
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen if ((ret = o_stream_flush(client->output)) < 0) {
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen o_stream_unset_flush_callback(client->output);
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainenvoid client_cmd_starttls(struct client *client)
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen client->v.notify_starttls(client, FALSE, "TLS is already active.");
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen client->v.notify_starttls(client, FALSE, "TLS support isn't enabled.");
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen /* remove input handler, SSL proxy gives us a new fd. we also have to
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen remove it in case we have to wait for buffer to be flushed */
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen client->v.notify_starttls(client, TRUE, "Begin TLS negotiation now.");
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen /* uncork the old fd */
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen /* the buffer has to be flushed */
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen o_stream_set_flush_pending(client->output, TRUE);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Siraineniostream_fd_proxy_finished(enum iostream_proxy_side side ATTR_UNUSED,
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen enum iostream_proxy_status status ATTR_UNUSED,
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen /* Destroy the proxy now. The other side of the proxy is still
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen unfinished and we don't want to get back here and unreference
b47c57ee07ccfe76cc23b23bc720e17fe9a46d5cTimo Sirainen the client twice. */
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen iostream_proxy_unref(&client->iostream_fd_proxy);
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainenint client_get_plaintext_fd(struct client *client, int *fd_r, bool *close_fd_r)
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen /* Plaintext connection - We can send the fd directly to
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen the post-login process without any proxying. */
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen /* We'll have to start proxying from now on until either side
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen disconnects. Create a socketpair where login process is proxying on
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen one side and the other side is sent to the post-login process. */
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) {
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen client_log_err(client, t_strdup_printf("socketpair() failed: %m"));
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen struct ostream *output = o_stream_create_fd(fds[0], IO_BLOCK_SIZE);
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen i_stream_create_fd_autoclose(&fds[0], IO_BLOCK_SIZE);
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen iostream_proxy_set_completion_callback(client->iostream_fd_proxy,
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen iostream_proxy_start(client->iostream_fd_proxy);
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainenunsigned int clients_get_count(void)
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainenunsigned int clients_get_fd_proxies_count(void)
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainenstruct client *clients_get_first_fd_proxy(void)
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainenvoid client_add_forward_field(struct client *client, const char *key,
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen client->forward_fields = str_new(client->preproxy_pool, 32);
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen /* prefixing is done by auth process */
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen str_append_tabescaped(client->forward_fields, key);
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen str_append_tabescaped(client->forward_fields, value);
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainenconst char *client_get_session_id(struct client *client)
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen unsigned int i;
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen buf = buffer_create_dynamic(pool_datastack_create(), 24);
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen base64_buf = buffer_create_dynamic(pool_datastack_create(), 24*2);
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen timestamp = tv.tv_usec + (long long)tv.tv_sec * 1000ULL*1000ULL;
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen /* add lowest 48 bits of the timestamp. this gives us a bit less than
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen 9 years until it wraps */
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen buffer_append_c(buf, (timestamp >> i) & 0xff);
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen buffer_append_c(buf, client->remote_port & 0xff);
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen buffer_append_c(buf, (client->remote_port >> 8) & 0xff);
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen buffer_append(buf, &client->ip.u.ip6, sizeof(client->ip.u.ip6));
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen buffer_append(buf, &client->ip.u.ip4, sizeof(client->ip.u.ip4));
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen base64_encode(buf->data, buf->used, base64_buf);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen client->session_id = p_strdup(client->pool, str_c(base64_buf));
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainenstatic struct var_expand_table login_var_expand_empty_tab[] = {
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainenget_var_expand_users(struct var_expand_table *tab, const char *user)
e2ea49bd487d76b425e270321e9cf1e546642de0Timo Sirainen unsigned int i;
e2ea49bd487d76b425e270321e9cf1e546642de0Timo Sirainen for (i = 0; i < 3; i++)
e2ea49bd487d76b425e270321e9cf1e546642de0Timo Sirainen tab[i].value = str_sanitize(tab[i].value, 80);
e2ea49bd487d76b425e270321e9cf1e546642de0Timo Sirainenstatic const struct var_expand_table *
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen tab = t_malloc_no0(sizeof(login_var_expand_empty_tab));
e2ea49bd487d76b425e270321e9cf1e546642de0Timo Sirainen get_var_expand_users(tab, client->virtual_user);
e2ea49bd487d76b425e270321e9cf1e546642de0Timo Sirainen tab[5].value = net_ip2addr(&client->local_ip);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen tab[8].value = client->auth_mech_name == NULL ? NULL :
e2ea49bd487d76b425e270321e9cf1e546642de0Timo Sirainen str_sanitize(client->auth_mech_name, MAX_MECH_NAME);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen tab[11].value = client->secured ? "secured" : NULL;
c48140ca508ebc9642737e7fd6c8d9e52f95df32Timo Sirainen tab[11].value = ssl_error == NULL ? ssl_state :
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen t_strdup_printf("%s: %s", ssl_state, ssl_error);
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen ssl_proxy_get_security_string(client->ssl_proxy);
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen tab[14].value = client_get_session_id(client);
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen tab[15].value = net_ip2addr(&client->real_local_ip);
c48140ca508ebc9642737e7fd6c8d9e52f95df32Timo Sirainen tab[16].value = net_ip2addr(&client->real_remote_ip);
c48140ca508ebc9642737e7fd6c8d9e52f95df32Timo Sirainen tab[17].value = dec2str(client->real_local_port);
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen tab[18].value = dec2str(client->real_remote_port);
c48140ca508ebc9642737e7fd6c8d9e52f95df32Timo Sirainen get_var_expand_users(tab+19, client->virtual_user_orig);
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen get_var_expand_users(tab+22, client->virtual_auth_user);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen tab[26].value = str_sanitize(client->local_name, 256);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenclient_var_expand_func_passdb(const char *data, void *context,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const char **value_r,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int i;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen for (i = 0; client->auth_passdb_args[i] != NULL; i++) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (strncmp(client->auth_passdb_args[i], field_name,
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen client->auth_passdb_args[i][field_name_len] == '=') {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *value_r = client->auth_passdb_args[i] + field_name_len+1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic const char *
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainenclient_get_log_str(struct client *client, const char *msg)
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen static const struct var_expand_func_table func_table[] = {
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen const struct var_expand_table *var_expand_table;
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen char *const *e;
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen unsigned int pos;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen var_expand_table = get_var_expand_table(client);
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen for (e = client->set->log_format_elements_split; *e != NULL; e++) {
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen if (var_expand_with_funcs(str, *e, var_expand_table,
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen i_error("Failed to expand log_format_elements=%s: %s",
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen /* username is added even if it's empty */
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen if (var_expand(str2, *e, login_var_expand_empty_tab,
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen /* we just logged this error above. no need
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen to do it again. */
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen if (strcmp(str_c(str)+pos, str_c(str2)) == 0) {
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen /* empty %variables, don't add */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (var_expand(str, client->set->login_log_format, tab, &error) <= 0) {
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen i_error("Failed to expand login_log_format=%s: %s",
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainenvoid client_log(struct client *client, const char *msg)
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen i_info("%s", client_get_log_str(client, msg));
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainenvoid client_log_err(struct client *client, const char *msg)
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen i_error("%s", client_get_log_str(client, msg));
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainenvoid client_log_warn(struct client *client, const char *msg)
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen i_warning("%s", client_get_log_str(client, msg));
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainenbool client_is_tls_enabled(struct client *client)
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen return ssl_initialized && strcmp(client->ssl_set->ssl, "no") != 0;
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainenconst char *client_get_extra_disconnect_reason(struct client *client)
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen unsigned int auth_secs = client->auth_first_started == 0 ? 0 :
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen if (client->set->auth_ssl_require_client_cert &&
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen if (ssl_proxy_has_broken_client_cert(client->ssl_proxy))
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen return "(client sent an invalid cert)";
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen if (!ssl_proxy_has_valid_client_cert(client->ssl_proxy))
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen return "(client didn't send a cert)";
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen "(disconnected before auth was ready, waited %u secs)",
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen (unsigned int)(ioloop_time - client->created));
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen /* disconnected by a plugin */
c9f1a617593eb569fb02f45041bad3c13e534496Timo Sirainen return t_strdup_printf("(no auth attempts in %u secs)",
c9f1a617593eb569fb02f45041bad3c13e534496Timo Sirainen (unsigned int)(ioloop_time - client->created));
c9f1a617593eb569fb02f45041bad3c13e534496Timo Sirainen /* some auth attempts without SSL/TLS */
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen if (client->set->auth_ssl_require_client_cert &&
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen return "(cert required, client didn't start TLS)";
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen if (client->auth_waiting && client->auth_attempts == 1) {
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen return t_strdup_printf("(client didn't finish SASL auth, "
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen if (client->auth_request != NULL && client->auth_attempts == 1) {
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen return t_strdup_printf("(disconnected while authenticating, "
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen if (client->authenticating && client->auth_attempts == 1) {
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen return t_strdup_printf("(disconnected while finishing login, "
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen if (client->auth_try_aborted && client->auth_attempts == 1)
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen return "(aborted authentication)";
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen return "(auth process communication failure)";
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen return "(proxy dest auth failed)";
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen return t_strdup_printf("(internal failure, %u successful auths)",
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "(authorization failed, %u attempts in %u secs)",
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return "(auth service reported temporary failure)";
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen return "(user disabled)";
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return "(password expired)";
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return "(sent invalid base64 in response)";
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return "(login disabled)";
d22390f33eedbd2413debabc0662dde5241b1aa6Timo Sirainen return "(tried to use unsupported auth mechanism)";
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return "(tried to use disallowed plaintext auth)";
d22390f33eedbd2413debabc0662dde5241b1aa6Timo Sirainen return t_strdup_printf("(auth failed, %u attempts in %u secs)",
d22390f33eedbd2413debabc0662dde5241b1aa6Timo Sirainenvoid client_notify_disconnect(struct client *client,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client->v.notify_disconnect(client, reason, text);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid client_notify_auth_ready(struct client *client)
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainenvoid client_notify_status(struct client *client, bool bad, const char *text)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid client_common_send_raw_data(struct client *client,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ret = o_stream_send(client->output, data, size);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* either disconnection or buffer full. in either case we want
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen this connection destroyed. however destroying it here might
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen break things if client is still tried to be accessed without
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen being referenced.. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid client_send_raw_data(struct client *client, const void *data, size_t size)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid client_send_raw(struct client *client, const char *data)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client_send_raw_data(client, data, strlen(data));
86bc22621dcce6d9f1ca7216c9cc958381a61277Timo Sirainen /* buffer full */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "Input buffer full, aborting");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client_destroy(client, "Disconnected: Input buffer full");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* disconnected */
e687badfdd7f4001e9a89a80a2c4a79ec4bafc8dTimo Sirainen /* nothing new read */
e687badfdd7f4001e9a89a80a2c4a79ec4bafc8dTimo Sirainen /* something was read */