bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
a7efba62b6235e5efc124cbf702ddeb547ca3665Timo Sirainenstatic struct client *client_fd_proxies = NULL;
0256180043b9f55b606b523b775e8b23b1b12f83Timo Sirainenstatic unsigned int client_fd_proxies_count = 0;
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainenstatic ARRAY(struct login_client_module_hooks) module_hooks = ARRAY_INIT;
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainenvoid login_client_hooks_add(struct module *module,
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainenvoid login_client_hooks_remove(const struct login_client_hooks *hooks)
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen const struct login_client_module_hooks *module_hook;
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen idx = array_foreach_idx(&module_hooks, module_hook);
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainenstatic void hook_login_client_allocated(struct client *client)
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen const struct login_client_module_hooks *module_hook;
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen ctx = hook_build_init((void *)&client->v, sizeof(client->v));
c5e62353a11087958ea4e619660e084a613e1a37Timo Sirainen if (module_hook->hooks->client_allocated != NULL) T_BEGIN {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic void client_idle_disconnect_timeout(struct client *client)
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen user_reason = "Timeout while finishing login.";
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen "Timeout while finishing login (waited %u secs)", secs);
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen "Disconnected for inactivity during authentication.";
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen "Disconnected: Inactivity during authentication";
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen user_reason = "Timeout while finishing login.";
7a94f950fd1dcc81537acfc8adb030b5e703d722Timo Sirainen "proxy: Logging in to %s:%u timed out "
2b96880f2d789d125aff6a95eaa7b51f558a6a1cTimo Sirainen "(state=%s, duration=%us)",
ed16ab579bd058ec5e2b5d02bb41fdadd9e05b31Timo Sirainen client_notify_disconnect(client, CLIENT_DISCONNECT_TIMEOUT, user_reason);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic void client_open_streams(struct client *client)
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 if (iostream_rawlog_create(login_rawlog_dir, &client->input,
12c6ef6f1268ed4d5b63709bb4215c481b4f078cTimo Sirainenstatic bool client_is_trusted(struct client *client)
12c6ef6f1268ed4d5b63709bb4215c481b4f078cTimo Sirainen if (client->set->login_trusted_networks == NULL)
12c6ef6f1268ed4d5b63709bb4215c481b4f078cTimo Sirainen net = t_strsplit_spaces(client->set->login_trusted_networks, ", ");
12c6ef6f1268ed4d5b63709bb4215c481b4f078cTimo Sirainen if (net_parse_range(*net, &net_ip, &bits) < 0) {
12c6ef6f1268ed4d5b63709bb4215c481b4f078cTimo Sirainen if (net_is_in_network(&client->ip, &net_ip, bits))
66ea9eaaa2d7531b3be8f633937628c94d907031Timo Sirainen const struct master_service_ssl_settings *ssl_set)
5a250816ffc4cc5db203f9410ea99b6601c7b91aTimo Sirainen client = login_binary->client_vfuncs->alloc(pool);
46ec792dd4ccf6c34706c4774228301fafde6aa9Timo Sirainen client->v.auth_send_challenge = client_auth_send_challenge;
46ec792dd4ccf6c34706c4774228301fafde6aa9Timo Sirainen client->v.auth_parse_response = client_auth_parse_response;
b045b66988bfbaa2795791e42ee724fae6f0db1cAki Tuomi client->preproxy_pool = pool_alloconly_create(MEMPOOL_GROWING"preproxy pool", 256);
9132f9df4e12ed5293c70957813aa3736444a13cTimo Sirainen p_array_init(&client->module_contexts, client->pool, 5);
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);
b6fbc235f981b10333403e2fd6d333fd351c7a3cAki Tuomi client->secured = conn->proxy.ssl || client->trusted;
b6fbc235f981b10333403e2fd6d333fd351c7a3cAki Tuomi client->client_cert_common_name = conn->proxy.cert_common_name;
b6fbc235f981b10333403e2fd6d333fd351c7a3cAki Tuomi net_ip_compare(&conn->real_remote_ip, &conn->real_local_ip);
66ea9eaaa2d7531b3be8f633937628c94d907031Timo Sirainenvoid client_init(struct client *client, void **other_sets)
dfafc4ac89195b8cdd48afa619599d5b392ef479Stephan Boschvoid client_disconnect(struct client *client, const char *reason)
1a1159e589def1e32b7dc25397f15146672ef73eTimo Sirainen !client->no_extra_disconnect_reason && reason != NULL) {
56af9dd10e7e6caeaca64395bad3f882b28ecdffTimo Sirainen reason = t_strconcat(reason, " ", extra_reason, NULL);
ac581db9a4ff22c5f99cf1666a0a1a7f7889e0a2Josef 'Jeff' Sipek ssl_iostream_destroy(&client->ssl_iostream);
cff2942962a11f78d23bcb0a4ed56f67e751819cJosef 'Jeff' Sipek iostream_proxy_unref(&client->iostream_fd_proxy);
1312cf655d3ea22c0ab6487ce710ad4060c25905Timo Sirainen /* Login was successful. We may now be proxying the connection,
1312cf655d3ea22c0ab6487ce710ad4060c25905Timo Sirainen so don't disconnect the client until client_unref(). */
935febe5d151719a9ddf1d2ba25449b19c76be04Timo Sirainen i_assert(client->prev == NULL && client->next == NULL);
dfafc4ac89195b8cdd48afa619599d5b392ef479Stephan Boschvoid client_destroy(struct client *client, const char *reason)
935febe5d151719a9ddf1d2ba25449b19c76be04Timo Sirainen /* remove from clients linked list before it's added to
935febe5d151719a9ddf1d2ba25449b19c76be04Timo Sirainen client_fd_proxies. */
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen master_auth_request_abort(master_auth, client->master_tag);
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&client->to_auth_waiting);
de754cb78f75e8b3b994cddafe41c9ed1467c33dTimo Sirainen dsasl_client_free(&client->proxy_sasl_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");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenvoid client_destroy_success(struct client *client, const char *reason)
ac581db9a4ff22c5f99cf1666a0a1a7f7889e0a2Josef 'Jeff' Sipek ssl_iostream_destroy(&client->ssl_iostream);
cff2942962a11f78d23bcb0a4ed56f67e751819cJosef 'Jeff' Sipek iostream_proxy_unref(&client->iostream_fd_proxy);
ec23e16ed879e289d12c6e1a5f9745dd3979004aTimo Sirainen master_service_client_connection_destroyed(master_service);
b84eff65e25ae86dfd6f798386577209b94838c6Timo Sirainenvoid client_common_default_free(struct client *client ATTR_UNUSED)
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen /* we have no clients */
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) {
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen client_notify_disconnect(client, CLIENT_DISCONNECT_RESOURCE_CONSTRAINT,
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen "Connection queue full");
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen client_destroy(client, "Disconnected: Connection queue full");
717bb0dbaf4bd3f745669570647845e6d493bfe0Timo Sirainenvoid clients_destroy_all_reason(const char *reason)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen for (client = clients; client != NULL; client = next) {
717bb0dbaf4bd3f745669570647845e6d493bfe0Timo Sirainen clients_destroy_all_reason("Disconnected: Shutting down");
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainenstatic int client_sni_callback(const char *name, const char **error_r,
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen client->local_name = p_strdup(client->pool, name);
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen client->set = login_settings_read(client->pool, &client->local_ip,
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen master_service_ssl_settings_to_iostream_set(client->ssl_set,
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 "Failed to initialize SSL server context: %s", error);
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen ssl_iostream_change_context(client->ssl_iostream, ssl_ctx);
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen master_service_ssl_settings_to_iostream_set(client->ssl_set,
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 if (ssl_iostream_server_context_cache_get(&ssl_set, &ssl_ctx, &error) < 0) {
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen "Failed to initialize SSL server context: %s", error));
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen if (io_stream_create_ssl_server(ssl_ctx, &ssl_set,
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen "Failed to initialize SSL connection: %s", error));
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen ssl_iostream_set_sni_callback(client->ssl_iostream,
b1485f2691de41ed7b5f96cebda2ebcb69a5e22fTimo Sirainenstatic void client_start_tls(struct client *client)
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen "TLS initialization failed.");
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen "Disconnected: TLS initialization failed.");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic int client_output_starttls(struct client *client)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if ((ret = o_stream_flush(client->output)) < 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen o_stream_unset_flush_callback(client->output);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenvoid client_cmd_starttls(struct client *client)
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen client->v.notify_starttls(client, FALSE, "TLS is already active.");
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen client->v.notify_starttls(client, FALSE, "TLS support isn't enabled.");
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 */
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen client->v.notify_starttls(client, TRUE, "Begin TLS negotiation now.");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* uncork the old fd */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* the buffer has to be flushed */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen o_stream_set_flush_pending(client->output, TRUE);
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Siraineniostream_fd_proxy_finished(enum iostream_proxy_side side ATTR_UNUSED,
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen enum iostream_proxy_status status ATTR_UNUSED,
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 Sirainenint client_get_plaintext_fd(struct client *client, int *fd_r, bool *close_fd_r)
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen /* Plaintext connection - We can send the fd directly to
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen the post-login process without any proxying. */
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 struct ostream *output = o_stream_create_fd(fds[0], IO_BLOCK_SIZE);
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen i_stream_create_fd_autoclose(&fds[0], IO_BLOCK_SIZE);
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen iostream_proxy_set_completion_callback(client->iostream_fd_proxy,
87dbf3e85526ccde5908a611eb9a798f1d0ccac3Timo Sirainen iostream_proxy_start(client->iostream_fd_proxy);
0256180043b9f55b606b523b775e8b23b1b12f83Timo Sirainenunsigned int clients_get_fd_proxies_count(void)
0256180043b9f55b606b523b775e8b23b1b12f83Timo Sirainenstruct client *clients_get_first_fd_proxy(void)
c4ec7cb598805b1387dc3aab59ec8f32d8cc24e1Timo Sirainenvoid client_add_forward_field(struct client *client, const char *key,
c4ec7cb598805b1387dc3aab59ec8f32d8cc24e1Timo Sirainen client->forward_fields = str_new(client->preproxy_pool, 32);
c4ec7cb598805b1387dc3aab59ec8f32d8cc24e1Timo Sirainen /* prefixing is done by auth process */
c4ec7cb598805b1387dc3aab59ec8f32d8cc24e1Timo Sirainen str_append_tabescaped(client->forward_fields, key);
c4ec7cb598805b1387dc3aab59ec8f32d8cc24e1Timo Sirainen str_append_tabescaped(client->forward_fields, value);
b55f914c0ade77252cfd798ea8eb9a84bda56315Timo Sirainenconst char *client_get_session_id(struct client *client)
b55f914c0ade77252cfd798ea8eb9a84bda56315Timo Sirainen unsigned int i;
b55f914c0ade77252cfd798ea8eb9a84bda56315Timo Sirainen timestamp = tv.tv_usec + (long long)tv.tv_sec * 1000ULL*1000ULL;
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 buffer_append_c(buf, (timestamp >> i) & 0xff);
b55f914c0ade77252cfd798ea8eb9a84bda56315Timo Sirainen buffer_append_c(buf, client->remote_port & 0xff);
a7d14da6cef3cfe26df5d039088ddd186c8aaedfTimo Sirainen buffer_append_c(buf, (client->remote_port >> 8) & 0xff);
b55f914c0ade77252cfd798ea8eb9a84bda56315Timo Sirainen buffer_append(buf, &client->ip.u.ip6, sizeof(client->ip.u.ip6));
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));
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainenstatic struct var_expand_table login_var_expand_empty_tab[] = {
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainenget_var_expand_users(struct var_expand_table *tab, const char *user)
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen unsigned int i;
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen for (i = 0; i < 3; i++)
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen tab[i].value = str_sanitize(tab[i].value, 80);
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainenstatic const struct var_expand_table *
0175d37a5ae5a4d146ca41b684bd38d9b03683cbMartti Rannanjärvi tab = t_malloc_no0(sizeof(login_var_expand_empty_tab));
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen get_var_expand_users(tab, client->virtual_user);
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen tab[5].value = net_ip2addr(&client->local_ip);
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[11].value = client->secured ? "secured" : NULL;
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen ssl_iostream_is_handshaked(client->ssl_iostream) ?
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen ssl_iostream_get_last_error(client->ssl_iostream);
bb8d0ec26bdd548624d7a7424071cca693b72f55Timo Sirainen tab[11].value = ssl_error == NULL ? ssl_state :
bb8d0ec26bdd548624d7a7424071cca693b72f55Timo Sirainen t_strdup_printf("%s: %s", ssl_state, ssl_error);
feb8f7b9490ddef989094ee21d7d1a222ccc4cb2Timo Sirainen ssl_iostream_get_security_string(client->ssl_iostream);
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 get_var_expand_users(tab+19, client->virtual_user_orig);
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen get_var_expand_users(tab+22, client->virtual_auth_user);
290b91ad6f5ea9e44b2d86b68dd80f0313cd2c57Aki Tuomi tab[26].value = str_sanitize(client->local_name, 256);
bcf1cf2afb9692b0db555e6ecf662a2fbd19793dTimo Sirainenclient_var_expand_func_passdb(const char *data, void *context,
bcf1cf2afb9692b0db555e6ecf662a2fbd19793dTimo Sirainen const char **value_r,
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen unsigned int i;
2dfd08e8aa16dfcc975d8a62bc8d20b2ef849d71Timo Sirainen for (i = 0; client->auth_passdb_args[i] != NULL; i++) {
2dfd08e8aa16dfcc975d8a62bc8d20b2ef849d71Timo Sirainen if (strncmp(client->auth_passdb_args[i], field_name,
bcf1cf2afb9692b0db555e6ecf662a2fbd19793dTimo Sirainen client->auth_passdb_args[i][field_name_len] == '=') {
bcf1cf2afb9692b0db555e6ecf662a2fbd19793dTimo Sirainen *value_r = client->auth_passdb_args[i] + field_name_len+1;
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainenstatic const char *
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainenclient_get_log_str(struct client *client, const char *msg)
2dfd08e8aa16dfcc975d8a62bc8d20b2ef849d71Timo Sirainen static const struct var_expand_func_table func_table[] = {
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen const struct var_expand_table *var_expand_table;
97db4761382024093f441e4bc78ba8b6a056504dTimo Sirainen char *const *e;
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen var_expand_table = get_var_expand_table(client);
97db4761382024093f441e4bc78ba8b6a056504dTimo Sirainen for (e = client->set->log_format_elements_split; *e != NULL; e++) {
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen if (var_expand_with_funcs(str, *e, var_expand_table,
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen i_error("Failed to expand log_format_elements=%s: %s",
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen /* username is added even if it's empty */
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen if (var_expand(str2, *e, login_var_expand_empty_tab,
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen /* we just logged this error above. no need
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen to do it again. */
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen if (strcmp(str_c(str)+pos, str_c(str2)) == 0) {
b5917cf6476ffb7cdeb2e2544057ea1605ea6fdcTimo Sirainen /* empty %variables, don't add */
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",
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenvoid client_log(struct client *client, const char *msg)
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen i_info("%s", client_get_log_str(client, msg));
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenvoid client_log_err(struct client *client, const char *msg)
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen i_error("%s", client_get_log_str(client, msg));
b9c76fe9d9ca194816606342da1ddbd9be6bc8abTimo Sirainenvoid client_log_warn(struct client *client, const char *msg)
b9c76fe9d9ca194816606342da1ddbd9be6bc8abTimo Sirainen i_warning("%s", client_get_log_str(client, msg));
6a9e034441607c0c5a61858ff559af4615ac31caTimo Sirainenbool client_is_tls_enabled(struct client *client)
3e06f836ce9c97ad09c7cb4b5660c5787900c1c6Timo Sirainen return login_ssl_initialized && strcmp(client->ssl_set->ssl, "no") != 0;
38318f5e82662615cd88e99e398efe4a630ce020Timo Sirainenconst char *client_get_extra_disconnect_reason(struct client *client)
28dae6a0064e79f86da091625b0f2b92336a2a91Timo Sirainen unsigned int auth_secs = client->auth_first_started == 0 ? 0 :
434abef12f61881a5cfa28d27193d0854a9639a0Timo Sirainen if (client->set->auth_ssl_require_client_cert &&
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)";
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen "(disconnected before auth was ready, waited %u secs)",
b9c76fe9d9ca194816606342da1ddbd9be6bc8abTimo Sirainen (unsigned int)(ioloop_time - client->created));
56af9dd10e7e6caeaca64395bad3f882b28ecdffTimo Sirainen /* disconnected by a plugin */
28dae6a0064e79f86da091625b0f2b92336a2a91Timo Sirainen return t_strdup_printf("(no auth attempts in %u secs)",
28dae6a0064e79f86da091625b0f2b92336a2a91Timo Sirainen (unsigned int)(ioloop_time - client->created));
38318f5e82662615cd88e99e398efe4a630ce020Timo Sirainen /* some auth attempts without SSL/TLS */
b4b87fa19d26aadb2ea9e8a9ae7af6cfdaab4cfbTimo Sirainen if (client->set->auth_ssl_require_client_cert &&
38318f5e82662615cd88e99e398efe4a630ce020Timo Sirainen return "(cert required, client didn't start TLS)";
6998ca95b4947c90647ac5d4794ebd6311acada2Timo Sirainen if (client->auth_waiting && client->auth_attempts == 1) {
6998ca95b4947c90647ac5d4794ebd6311acada2Timo Sirainen return t_strdup_printf("(client didn't finish SASL auth, "
28dae6a0064e79f86da091625b0f2b92336a2a91Timo Sirainen if (client->auth_request != NULL && client->auth_attempts == 1) {
28dae6a0064e79f86da091625b0f2b92336a2a91Timo Sirainen return t_strdup_printf("(disconnected while authenticating, "
28dae6a0064e79f86da091625b0f2b92336a2a91Timo Sirainen if (client->authenticating && client->auth_attempts == 1) {
28dae6a0064e79f86da091625b0f2b92336a2a91Timo Sirainen return t_strdup_printf("(disconnected while finishing login, "
3ffb7fd86484c474b42f3f1e981ab0f7168b5df9Timo Sirainen if (client->auth_try_aborted && client->auth_attempts == 1)
3ffb7fd86484c474b42f3f1e981ab0f7168b5df9Timo Sirainen return "(aborted authentication)";
7c849dbc7be089175c1a83a84ee7249ed695810dTimo Sirainen return "(auth process communication failure)";
80980955bb1bbcc1bd73623fe0912f334194ddd2Timo Sirainen return "(proxy dest auth failed)";
3f878e1442c881e4c5a80661b391926bcdee6016Timo Sirainen return t_strdup_printf("(internal failure, %u successful auths)",
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch "(authorization failed, %u attempts in %u secs)",
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch return "(auth service reported temporary failure)";
ca843e046e98b12f4730f4b87ee2e1a659c26e78Timo Sirainen return "(user disabled)";
ca843e046e98b12f4730f4b87ee2e1a659c26e78Timo Sirainen return "(password expired)";
8ac6623677005256bf99ab33a2ed98c69c1d656cStephan Bosch return "(sent invalid base64 in response)";
f32d0295c90ed810889504cdfa5e1a25a415f65fStephan Bosch return "(login disabled)";
04eb0abcf8f8b0c014499b5c5bae89484553613fStephan Bosch return "(tried to use unsupported auth mechanism)";
04eb0abcf8f8b0c014499b5c5bae89484553613fStephan Bosch return "(tried to use disallowed plaintext auth)";
28dae6a0064e79f86da091625b0f2b92336a2a91Timo Sirainen return t_strdup_printf("(auth failed, %u attempts in %u secs)",
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainenvoid client_notify_disconnect(struct client *client,
ab90f702ceedb7ba445a9a592be0b213b27cbafaStephan Bosch client->v.notify_disconnect(client, reason, text);
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainenvoid client_notify_auth_ready(struct client *client)
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainenvoid client_notify_status(struct client *client, bool bad, const char *text)
ae797f3368ebb86e7786ca25d7c9c703f672b9f5Timo Sirainenvoid client_common_send_raw_data(struct client *client,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen ret = o_stream_send(client->output, data, 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.. */
ae797f3368ebb86e7786ca25d7c9c703f672b9f5Timo Sirainenvoid client_send_raw_data(struct client *client, const void *data, size_t size)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenvoid client_send_raw(struct client *client, const char *data)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_send_raw_data(client, data, strlen(data));
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* buffer full */
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen "Input buffer full, aborting");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_destroy(client, "Disconnected: Input buffer full");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* disconnected */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* nothing new read */
a074b1e4012665af44b198a05baa5e478220ec3fTimo Sirainen return i_stream_get_data_size(client->input) > 0;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* something was read */