client-common.c revision 0266a571e98246e2e1b9dd7fe0301e21e226929a
a8c5a86d183db25a57bf193c06b41e092ec2e151Timo Sirainen/* Copyright (c) 2002-2009 Dovecot authors, see the included COPYING file */
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
08d6658a4e2ec8104cd1307f6baa75fdb07a24f8Mark Washenberger#include "common.h"
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen#include "hostpid.h"
6789ed17e7ca4021713507baf0dcf6979bb42e0cTimo Sirainen#include "llist.h"
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen#include "istream.h"
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen#include "ostream.h"
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen#include "process-title.h"
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen#include "str.h"
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen#include "str-sanitize.h"
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen#include "safe-memset.h"
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen#include "var-expand.h"
08d6658a4e2ec8104cd1307f6baa75fdb07a24f8Mark Washenberger#include "master-service.h"
06ff2a72c39cb34cc6425f17fc82c5e93fef2018Timo Sirainen#include "master-auth.h"
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen#include "auth-client.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "login-proxy.h"
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen#include "ssl-proxy.h"
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen#include "client-common.h"
de76b960297406115cf6bae473f004c08174b16aTimo Sirainen
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen#include <stdlib.h>
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen
c519de264df14a9d525e2604671c332590ce54e3Timo Sirainen/* When max. number of simultaneous connections is reached, few of the
61530b48694398df42744204e35535dbe3f745c4Timo Sirainen oldest connections are disconnected. Since we have to go through all of the
61530b48694398df42744204e35535dbe3f745c4Timo Sirainen clients, it's faster if we disconnect multiple clients. */
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen#define CLIENT_DESTROY_OLDEST_COUNT 16
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenstruct client *clients = NULL;
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainenstatic unsigned int clients_count = 0;
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen
6789ed17e7ca4021713507baf0dcf6979bb42e0cTimo Sirainenstatic void client_idle_disconnect_timeout(struct client *client)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen{
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen client_send_line(client, CLIENT_CMD_REPLY_BAD,
6789ed17e7ca4021713507baf0dcf6979bb42e0cTimo Sirainen "Disconnected for inactivity.");
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen client_destroy(client, "Disconnected: Inactivity");
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen}
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2b3b0df76184799317584b596af8df5afec3ebddTimo Sirainenstatic void client_open_streams(struct client *client)
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen{
6789ed17e7ca4021713507baf0dcf6979bb42e0cTimo Sirainen client->input =
6789ed17e7ca4021713507baf0dcf6979bb42e0cTimo Sirainen i_stream_create_fd(client->fd, LOGIN_MAX_INBUF_SIZE, FALSE);
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen client->output =
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen o_stream_create_fd(client->fd, LOGIN_MAX_OUTBUF_SIZE, FALSE);
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen}
d244c6cadd5f077f5d0f1e00c3652d0108a2d908Timo Sirainen
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainenstruct client *client_create(int fd, bool ssl, pool_t pool,
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen const struct login_settings *set,
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen const struct ip_addr *local_ip,
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen const struct ip_addr *remote_ip)
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen{
d244c6cadd5f077f5d0f1e00c3652d0108a2d908Timo Sirainen struct client *client;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen i_assert(fd != -1);
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen
d244c6cadd5f077f5d0f1e00c3652d0108a2d908Timo Sirainen if (clients_get_count() >= set->login_max_connections) {
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen /* reached max. users count, kill few of the
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen oldest connections */
baf1148108b7d9739626b47cc57298c36929586aTimo Sirainen client_destroy_oldest();
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen }
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen
baf1148108b7d9739626b47cc57298c36929586aTimo Sirainen /* always use nonblocking I/O */
baf1148108b7d9739626b47cc57298c36929586aTimo Sirainen net_set_nonblock(fd, TRUE);
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen client = client_vfuncs.alloc(pool);
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen client->v = client_vfuncs;
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen if (client->v.auth_send_challenge == NULL)
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen client->v.auth_send_challenge = client_auth_send_challenge;
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen if (client->v.auth_parse_response == NULL)
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen client->v.auth_parse_response = client_auth_parse_response;
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen client->created = ioloop_time;
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen client->refcount = 1;
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen client->pool = pool;
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen client->set = set;
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen client->local_ip = *local_ip;
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen client->ip = *remote_ip;
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen client->fd = fd;
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen client->tls = ssl;
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen client->trusted = client_is_trusted(client);
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen client->secured = ssl || client->trusted ||
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen net_ip_compare(remote_ip, local_ip);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen DLLIST_PREPEND(&clients, client);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen clients_count++;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen client_set_title(client);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen client->to_idle_disconnect =
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen timeout_add(CLIENT_LOGIN_IDLE_TIMEOUT_MSECS,
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen client_idle_disconnect_timeout, client);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen client_open_streams(client);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen client->v.create(client);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (auth_client_is_connected(auth_client))
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen client->v.send_greeting(client);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen else
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen client_set_auth_waiting(client);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return client;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen}
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenvoid client_destroy(struct client *client, const char *reason)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen{
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (client->destroyed)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen client->destroyed = TRUE;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (!client->login_success && reason != NULL) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen reason = t_strconcat(reason, " ",
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen client_get_extra_disconnect_reason(client), NULL);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen }
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (reason != NULL)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen client_log(client, reason);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen i_assert(clients_count > 0);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen clients_count--;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen DLLIST_REMOVE(&clients, client);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen if (client->input != NULL)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen i_stream_close(client->input);
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen if (client->output != NULL)
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen o_stream_close(client->output);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen if (client->master_tag != 0) {
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen i_assert(client->auth_request == NULL);
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen i_assert(client->authenticating);
8039af9679af6fb56116b353fe44f7dd4c08f031Timo Sirainen master_auth_request_abort(master_service, client->master_tag);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen } else if (client->auth_request != NULL) {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen i_assert(client->authenticating);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen sasl_server_auth_abort(client);
2cfe9983ce7a6280636ee12beccc2e865111967bTimo Sirainen } else {
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen i_assert(!client->authenticating);
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen }
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (client->io != NULL)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen io_remove(&client->io);
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen if (client->to_idle_disconnect != NULL)
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen timeout_remove(&client->to_idle_disconnect);
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen if (client->to_auth_waiting != NULL)
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen timeout_remove(&client->to_auth_waiting);
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen if (client->to_authfail_delay != NULL)
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen timeout_remove(&client->to_authfail_delay);
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen if (client->auth_response != NULL)
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen str_free(&client->auth_response);
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen if (client->fd != -1) {
e20e638805c4bd54e039891a3e92760b1dfa189aTimo Sirainen net_disconnect(client->fd);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen client->fd = -1;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (client->proxy_password != NULL) {
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen safe_memset(client->proxy_password, 0,
e20e638805c4bd54e039891a3e92760b1dfa189aTimo Sirainen strlen(client->proxy_password));
e20e638805c4bd54e039891a3e92760b1dfa189aTimo Sirainen i_free_and_null(client->proxy_password);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_free_and_null(client->proxy_user);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_free_and_null(client->proxy_master_user);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (client->login_proxy != NULL)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen login_proxy_free(&client->login_proxy);
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen if (client->ssl_proxy != NULL)
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen ssl_proxy_free(&client->ssl_proxy);
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen client->v.destroy(client);
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen client_unref(client);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen}
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainenvoid client_destroy_success(struct client *client, const char *reason)
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen{
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen client->login_success = TRUE;
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen client_destroy(client, reason);
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen}
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainenvoid client_destroy_internal_failure(struct client *client)
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen{
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen client_send_line(client, CLIENT_CMD_REPLY_AUTH_FAIL_TEMP,
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen "Internal login failure. "
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen "Refer to server log for more information.");
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen client_destroy(client, "Internal login failure");
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen}
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
905951e448e0d0f0778f43ce7673d0cac60b9b61Timo Sirainenvoid client_ref(struct client *client)
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen{
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen client->refcount++;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen}
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainenbool client_unref(struct client *client)
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen{
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen i_assert(client->refcount > 0);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen if (--client->refcount > 0)
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen return TRUE;
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen i_assert(client->destroyed);
905951e448e0d0f0778f43ce7673d0cac60b9b61Timo Sirainen
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen if (client->input != NULL)
905951e448e0d0f0778f43ce7673d0cac60b9b61Timo Sirainen i_stream_unref(&client->input);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen if (client->output != NULL)
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen o_stream_unref(&client->output);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen if (!client->proxying) {
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen i_assert(client->ssl_proxy == NULL);
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen master_service_client_connection_destroyed(master_service);
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen }
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen i_free(client->virtual_user);
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen i_free(client->auth_mech_name);
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen pool_unref(&client->pool);
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen return FALSE;
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen}
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainenvoid client_destroy_oldest(void)
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen{
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen unsigned int max_connections =
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen global_login_settings->login_max_connections;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen struct client *client;
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen struct client *destroy_buf[CLIENT_DESTROY_OLDEST_COUNT];
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen unsigned int i, destroy_count;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen /* find the oldest clients and put them to destroy-buffer */
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen memset(destroy_buf, 0, sizeof(destroy_buf));
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen destroy_count = max_connections > CLIENT_DESTROY_OLDEST_COUNT*2 ?
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen CLIENT_DESTROY_OLDEST_COUNT : I_MIN(max_connections/2, 1);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen for (client = clients; client != NULL; client = client->next) {
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen for (i = 0; i < destroy_count; i++) {
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen if (destroy_buf[i] == NULL ||
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen destroy_buf[i]->created > client->created) {
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen /* @UNSAFE */
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen memmove(destroy_buf+i+1, destroy_buf+i,
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen sizeof(destroy_buf) -
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen (i+1) * sizeof(destroy_buf[0]));
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen destroy_buf[i] = client;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen break;
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen }
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen }
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen }
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen /* then kill them */
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen for (i = 0; i < destroy_count; i++) {
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen if (destroy_buf[i] == NULL)
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen break;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
217cdf98fe6f3e5a9a932e41fa2e956c153a6947Timo Sirainen client_destroy(destroy_buf[i],
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen "Disconnected: Connection queue full");
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen }
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen}
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainenvoid clients_destroy_all(void)
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen{
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen struct client *client, *next;
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen for (client = clients; client != NULL; client = next) {
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen next = client->next;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen client_destroy(client, "Disconnected: Shutting down");
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen }
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen}
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainenstatic void client_start_tls(struct client *client)
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen{
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen int fd_ssl;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
cdc5c81463995a153c57c68c299e98cc3de0b287Timo Sirainen client_ref(client);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen if (!client_unref(client) || client->destroyed)
cdc5c81463995a153c57c68c299e98cc3de0b287Timo Sirainen return;
cdc5c81463995a153c57c68c299e98cc3de0b287Timo Sirainen
cdc5c81463995a153c57c68c299e98cc3de0b287Timo Sirainen fd_ssl = ssl_proxy_new(client->fd, &client->ip,
cdc5c81463995a153c57c68c299e98cc3de0b287Timo Sirainen client->set, &client->ssl_proxy);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen if (fd_ssl == -1) {
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen client_send_line(client, CLIENT_CMD_REPLY_BYE,
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen "TLS initialization failed.");
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen client_destroy(client,
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen "Disconnected: TLS initialization failed.");
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen return;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen }
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen client->starttls = TRUE;
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen client->proxying = TRUE;
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen client->tls = TRUE;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen client->secured = TRUE;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen client_set_title(client);
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen client->fd = fd_ssl;
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen client->io = io_add(client->fd, IO_READ, client_input, client);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen i_stream_unref(&client->input);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen o_stream_unref(&client->output);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen client_open_streams(client);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen client->v.starttls(client);
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen}
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainenstatic int client_output_starttls(struct client *client)
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen{
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen int ret;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen if ((ret = o_stream_flush(client->output)) < 0) {
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen client_destroy(client, "Disconnected");
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen return 1;
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen }
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen if (ret > 0) {
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen o_stream_unset_flush_callback(client->output);
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen client_start_tls(client);
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen }
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen return 1;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen}
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainenvoid client_cmd_starttls(struct client *client)
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen{
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen if (client->tls) {
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen client_send_line(client, CLIENT_CMD_REPLY_BAD,
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen "TLS is already active.");
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen return;
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen }
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen if (!ssl_initialized) {
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen client_send_line(client, CLIENT_CMD_REPLY_BAD,
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen "TLS support isn't enabled.");
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen return;
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen }
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen /* remove input handler, SSL proxy gives us a new fd. we also have to
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen remove it in case we have to wait for buffer to be flushed */
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen if (client->io != NULL)
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen io_remove(&client->io);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen client_send_line(client, CLIENT_CMD_REPLY_OK,
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen "Begin TLS negotiation now.");
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen /* uncork the old fd */
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen o_stream_uncork(client->output);
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen if (o_stream_flush(client->output) <= 0) {
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen /* the buffer has to be flushed */
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen o_stream_set_flush_pending(client->output, TRUE);
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen o_stream_set_flush_callback(client->output,
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen client_output_starttls, client);
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen } else {
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen client_start_tls(client);
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen}
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainenunsigned int clients_get_count(void)
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen{
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen return clients_count;
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen}
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainenvoid client_set_title(struct client *client)
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen{
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen const char *addr;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (!client->set->verbose_proctitle ||
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen master_service_get_client_limit(master_service) > 1)
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen return;
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen addr = net_ip2addr(&client->ip);
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen if (addr == NULL)
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen addr = "??";
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen process_title_set(t_strdup_printf(client->tls ?
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen "[%s TLS]" : "[%s]", addr));
a342a31752dd71ac444259ca57ad33ea6b79a572Timo Sirainen}
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenstatic const struct var_expand_table *
31a574fda352ef4f71dbff9c30e15e4744e132c0Timo Sirainenget_var_expand_table(struct client *client)
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen{
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen static struct var_expand_table static_tab[] = {
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen { 'u', NULL, "user" },
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen { 'n', NULL, "username" },
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen { 'd', NULL, "domain" },
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen { 's', NULL, "service" },
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen { 'h', NULL, "home" },
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen { 'l', NULL, "lip" },
75d03475effdfaaf9bbf5fdb07b056bca62f14c1Timo Sirainen { 'r', NULL, "rip" },
75d03475effdfaaf9bbf5fdb07b056bca62f14c1Timo Sirainen { 'p', NULL, "pid" },
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen { 'm', NULL, "mech" },
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen { 'a', NULL, "lport" },
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen { 'b', NULL, "rport" },
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen { 'c', NULL, "secured" },
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen { 'k', NULL, "ssl_security" },
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen { 'e', NULL, "mail_pid" },
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen { '\0', NULL, NULL }
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen };
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen struct var_expand_table *tab;
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen unsigned int i;
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen tab = t_malloc(sizeof(static_tab));
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen memcpy(tab, static_tab, sizeof(static_tab));
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen if (client->virtual_user != NULL) {
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen tab[0].value = client->virtual_user;
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen tab[1].value = t_strcut(client->virtual_user, '@');
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen tab[2].value = strchr(client->virtual_user, '@');
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen if (tab[2].value != NULL) tab[2].value++;
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen for (i = 0; i < 3; i++)
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen tab[i].value = str_sanitize(tab[i].value, 80);
2412873209ff658bc4bd20123af2d6162464c4ffTimo Sirainen }
2412873209ff658bc4bd20123af2d6162464c4ffTimo Sirainen tab[3].value = login_protocol;
2412873209ff658bc4bd20123af2d6162464c4ffTimo Sirainen tab[4].value = getenv("HOME");
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen tab[5].value = net_ip2addr(&client->local_ip);
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen tab[6].value = net_ip2addr(&client->ip);
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen tab[7].value = my_pid;
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen tab[8].value = client->auth_mech_name == NULL ? NULL :
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen str_sanitize(client->auth_mech_name, MAX_MECH_NAME);
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen tab[9].value = dec2str(client->local_port);
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen tab[10].value = dec2str(client->remote_port);
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen if (!client->tls) {
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen tab[11].value = client->secured ? "secured" : NULL;
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen tab[12].value = "";
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen } else {
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen const char *ssl_state =
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen ssl_proxy_is_handshaked(client->ssl_proxy) ?
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen "TLS" : "TLS handshaking";
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen const char *ssl_error =
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen ssl_proxy_get_last_error(client->ssl_proxy);
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen tab[11].value = ssl_error == NULL ? ssl_state :
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen t_strdup_printf("%s: %s", ssl_state, ssl_error);
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen tab[12].value =
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen ssl_proxy_get_security_string(client->ssl_proxy);
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen }
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen tab[13].value = dec2str(client->mail_pid);
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen return tab;
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen}
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainenstatic bool have_key(const struct var_expand_table *table, const char *str)
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen{
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen char key;
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen unsigned int i;
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen key = var_get_key(str);
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen for (i = 0; table[i].key != '\0'; i++) {
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen if (table[i].key == key) {
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen return table[i].value != NULL &&
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen table[i].value[0] != '\0';
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return FALSE;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen}
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainenstatic const char *
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainenclient_get_log_str(struct client *client, const char *msg)
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainen{
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainen static struct var_expand_table static_tab[3] = {
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainen { 's', NULL, NULL },
16a815d92a3202e3a66fd7f8e3478664b852bf1eTimo Sirainen { '$', NULL, NULL },
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen { '\0', NULL, NULL }
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen };
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen const struct var_expand_table *var_expand_table;
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainen struct var_expand_table *tab;
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen const char *p;
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen char *const *e;
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen string_t *str;
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainen
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainen var_expand_table = get_var_expand_table(client);
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainen
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainen tab = t_malloc(sizeof(static_tab));
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen memcpy(tab, static_tab, sizeof(static_tab));
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen str = t_str_new(256);
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen for (e = client->set->log_format_elements_split; *e != NULL; e++) {
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen for (p = *e; *p != '\0'; p++) {
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen if (*p != '%' || p[1] == '\0')
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen continue;
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen p++;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (have_key(var_expand_table, p)) {
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen if (str_len(str) > 0)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen str_append(str, ", ");
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen var_expand(str, *e, var_expand_table);
16a815d92a3202e3a66fd7f8e3478664b852bf1eTimo Sirainen break;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen tab[0].value = t_strdup(str_c(str));
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen tab[1].value = msg;
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen str_truncate(str, 0);
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen var_expand(str, client->set->login_log_format, tab);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return str_c(str);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen}
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainenvoid client_log(struct client *client, const char *msg)
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen{
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen T_BEGIN {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen i_info("%s", client_get_log_str(client, msg));
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen } T_END;
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen}
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainenvoid client_log_err(struct client *client, const char *msg)
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen{
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen T_BEGIN {
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen i_error("%s", client_get_log_str(client, msg));
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen } T_END;
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen}
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainenbool client_is_trusted(struct client *client)
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen{
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen const char *const *net;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen struct ip_addr net_ip;
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen unsigned int bits;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen if (client->set->login_trusted_networks == NULL)
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen return FALSE;
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen net = t_strsplit_spaces(client->set->login_trusted_networks, ", ");
16a815d92a3202e3a66fd7f8e3478664b852bf1eTimo Sirainen for (; *net != NULL; net++) {
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainen if (net_parse_range(*net, &net_ip, &bits) < 0) {
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainen i_error("login_trusted_networks: "
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainen "Invalid network '%s'", *net);
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen break;
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainen }
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen if (net_is_in_network(&client->ip, &net_ip, bits))
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen return TRUE;
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainen }
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainen return FALSE;
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen}
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainen
d21f14c01d5546f4bf1b2cbb28ac1f00c24d952aTimo Sirainenconst char *client_get_extra_disconnect_reason(struct client *client)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen{
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (client->set->ssl_require_client_cert && client->ssl_proxy != NULL) {
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen if (ssl_proxy_has_broken_client_cert(client->ssl_proxy))
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen return "(client sent an invalid cert)";
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen if (!ssl_proxy_has_valid_client_cert(client->ssl_proxy))
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen return "(client didn't send a cert)";
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen if (client->auth_attempts == 0)
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen return "(no auth attempts)";
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen /* some auth attempts without SSL/TLS */
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (client->auth_tried_disabled_plaintext)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return "(tried to use disabled plaintext auth)";
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen if (client->set->ssl_require_client_cert)
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen return "(cert required, client didn't start TLS)";
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
16a815d92a3202e3a66fd7f8e3478664b852bf1eTimo Sirainen return t_strdup_printf("(auth failed, %u attempts)",
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen client->auth_attempts);
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen}
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenvoid client_send_line(struct client *client, enum client_cmd_reply reply,
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen const char *text)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen{
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen client->v.send_line(client, reply, text);
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen}
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainenvoid client_send_raw_data(struct client *client, const void *data, size_t size)
16a815d92a3202e3a66fd7f8e3478664b852bf1eTimo Sirainen{
16a815d92a3202e3a66fd7f8e3478664b852bf1eTimo Sirainen ssize_t ret;
16a815d92a3202e3a66fd7f8e3478664b852bf1eTimo Sirainen
5a7acd67806132cbc1ec9578df60d712d307e4beTimo Sirainen ret = o_stream_send(client->output, data, size);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (ret < 0 || (size_t)ret != size) {
16a815d92a3202e3a66fd7f8e3478664b852bf1eTimo Sirainen /* either disconnection or buffer full. in either case we want
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen this connection destroyed. however destroying it here might
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen break things if client is still tried to be accessed without
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen being referenced.. */
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen i_stream_close(client->input);
16a815d92a3202e3a66fd7f8e3478664b852bf1eTimo Sirainen }
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen}
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenvoid client_send_raw(struct client *client, const char *data)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen{
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen client_send_raw_data(client, data, strlen(data));
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen}
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenbool client_read(struct client *client)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen{
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen switch (i_stream_read(client->input)) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen case -2:
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen /* buffer full */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen client_send_line(client, CLIENT_CMD_REPLY_BYE,
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen "Input buffer full, aborting");
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen client_destroy(client, "Disconnected: Input buffer full");
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return FALSE;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen case -1:
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen /* disconnected */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen client_destroy(client, "Disconnected");
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return FALSE;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen case 0:
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen /* nothing new read */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return TRUE;
16a815d92a3202e3a66fd7f8e3478664b852bf1eTimo Sirainen default:
16a815d92a3202e3a66fd7f8e3478664b852bf1eTimo Sirainen /* something was read */
16a815d92a3202e3a66fd7f8e3478664b852bf1eTimo Sirainen timeout_reset(client->to_idle_disconnect);
16a815d92a3202e3a66fd7f8e3478664b852bf1eTimo Sirainen return TRUE;
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen}
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen
79fcd3f95a6266cc62ceaa753e56dd4456ab7c4bTimo Sirainenvoid client_input(struct client *client)
6f84506cf692d4f4f1ac69498e936b27dabdb60cTimo Sirainen{
6f84506cf692d4f4f1ac69498e936b27dabdb60cTimo Sirainen client->v.input(client);
6f84506cf692d4f4f1ac69498e936b27dabdb60cTimo Sirainen}
6f84506cf692d4f4f1ac69498e936b27dabdb60cTimo Sirainen