client-common.c revision 8372fc7efb6d64dff2e5f55fb4a3822c56869cfe
e59faf65ce864fe95dc00f5d52b8323cdbd0608aTimo Sirainen/* Copyright (c) 2002-2008 Dovecot authors, see the included COPYING file */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include "common.h"
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include "hostpid.h"
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include "llist.h"
472369cba85d9f7c995dda60e7cd01d78b4a960aTimo Sirainen#include "str.h"
e28fa207d1a097fa6e4a867f74ee0761472ef1ceTimo Sirainen#include "str-sanitize.h"
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen#include "var-expand.h"
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen#include "ssl-proxy.h"
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen#include "client-common.h"
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen#include <stdlib.h>
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainenstruct client *clients = NULL;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainenstatic unsigned int clients_count = 0;
94d8e51119003d2bc5a100c663f90141f297385dTimo Sirainen
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainenvoid client_link(struct client *client)
e28fa207d1a097fa6e4a867f74ee0761472ef1ceTimo Sirainen{
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen DLLIST_PREPEND(&clients, client);
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen clients_count++;
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen}
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenvoid client_unlink(struct client *client)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen{
5694eeb99b69dea8033ca77ad69743c6b4871370Timo Sirainen i_assert(clients_count > 0);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
5694eeb99b69dea8033ca77ad69743c6b4871370Timo Sirainen clients_count--;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen DLLIST_REMOVE(&clients, client);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen}
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenunsigned int clients_get_count(void)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen{
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return clients_count;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen}
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic const struct var_expand_table *
de486b59018016977015ef42e6071155b60e82e1Timo Sirainenget_var_expand_table(struct client *client)
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen{
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen static struct var_expand_table static_tab[] = {
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen { 'u', NULL, "user" },
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen { 'n', NULL, "username" },
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen { 'd', NULL, "domain" },
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen { 's', NULL, "service" },
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen { 'h', NULL, "home" },
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen { 'l', NULL, "lip" },
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen { 'r', NULL, "rip" },
220e21750948941dc6e33b8f11b552fa21d7f81eTimo Sirainen { 'p', NULL, "pid" },
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen { 'm', NULL, "mech" },
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen { 'a', NULL, "lport" },
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen { 'b', NULL, "rport" },
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen { 'c', NULL, "secured" },
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen { 'k', NULL, "ssl_security" },
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen { 'e', NULL, "mail_pid" },
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen { '\0', NULL, NULL }
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen };
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen struct var_expand_table *tab;
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen unsigned int i;
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen tab = t_malloc(sizeof(static_tab));
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen memcpy(tab, static_tab, sizeof(static_tab));
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (client->virtual_user != NULL) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen tab[0].value = client->virtual_user;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen tab[1].value = t_strcut(client->virtual_user, '@');
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen tab[2].value = strchr(client->virtual_user, '@');
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (tab[2].value != NULL) tab[2].value++;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen for (i = 0; i < 3; i++)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen tab[i].value = str_sanitize(tab[i].value, 80);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen tab[3].value = login_protocol;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen tab[4].value = getenv("HOME");
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen tab[5].value = net_ip2addr(&client->local_ip);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen tab[6].value = net_ip2addr(&client->ip);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen tab[7].value = my_pid;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen tab[8].value = client->auth_mech_name == NULL ? NULL :
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen str_sanitize(client->auth_mech_name, MAX_MECH_NAME);
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen tab[9].value = dec2str(client->local_port);
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen tab[10].value = dec2str(client->remote_port);
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen if (!client->tls) {
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen tab[11].value = client->secured ? "secured" : NULL;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen tab[12].value = "";
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen } else {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen const char *ssl_state = ssl_proxy_is_handshaked(client->proxy) ?
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen "TLS" : "TLS handshaking";
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen const char *ssl_error = ssl_proxy_get_last_error(client->proxy);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen tab[11].value = ssl_error == NULL ? ssl_state :
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen t_strdup_printf("%s: %s", ssl_state, ssl_error);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen tab[12].value = ssl_proxy_get_security_string(client->proxy);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen tab[13].value = dec2str(client->mail_pid);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return tab;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen}
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic bool have_key(const struct var_expand_table *table, const char *str)
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen{
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen char key;
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen unsigned int i;
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen key = var_get_key(str);
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen for (i = 0; table[i].key != '\0'; i++) {
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen if (table[i].key == key) {
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen return table[i].value != NULL &&
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen table[i].value[0] != '\0';
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen }
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen }
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen return FALSE;
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen}
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenstatic const char *
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenclient_get_log_str(struct client *client, const char *msg)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen{
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen static struct var_expand_table static_tab[3] = {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen { 's', NULL, NULL },
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen { '$', NULL, NULL },
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen { '\0', NULL, NULL }
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen };
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen const struct var_expand_table *var_expand_table;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen struct var_expand_table *tab;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen const char *p, *const *e;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen string_t *str;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen var_expand_table = get_var_expand_table(client);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen tab = t_malloc(sizeof(static_tab));
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen memcpy(tab, static_tab, sizeof(static_tab));
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen str = t_str_new(256);
6600c05e2ab38e9f662582b63c56b0c980a03748Timo Sirainen for (e = log_format_elements; *e != NULL; e++) {
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen for (p = *e; *p != '\0'; p++) {
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen if (*p != '%' || p[1] == '\0')
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen continue;
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen p++;
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen if (have_key(var_expand_table, p)) {
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen if (str_len(str) > 0)
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen str_append(str, ", ");
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen var_expand(str, *e, var_expand_table);
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen break;
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen }
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen }
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen }
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen tab[0].value = t_strdup(str_c(str));
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen tab[1].value = msg;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen str_truncate(str, 0);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen var_expand(str, log_format, tab);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen return str_c(str);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen}
3fe67ec75ccae1230bb9eb9f16affc48377f6441Timo Sirainen
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainenvoid client_syslog(struct client *client, const char *msg)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen{
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen T_BEGIN {
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen i_info("%s", client_get_log_str(client, msg));
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen } T_END;
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen}
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainenvoid client_syslog_err(struct client *client, const char *msg)
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen{
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen T_BEGIN {
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen i_error("%s", client_get_log_str(client, msg));
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen } T_END;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen}
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenbool client_is_trusted(struct client *client)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen{
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen const char *const *net;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen struct ip_addr net_ip;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen unsigned int bits;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
27586e4785d56aeb76e1fd96af8db799688dc64aTimo Sirainen if (trusted_networks == NULL)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen return FALSE;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen net = t_strsplit_spaces(trusted_networks, ", ");
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen for (; *net != NULL; net++) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (net_parse_range(*net, &net_ip, &bits) < 0) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen i_error("login_trusted_networks: "
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen "Invalid network '%s'", *net);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen break;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen }
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (net_is_in_network(&client->ip, &net_ip, bits))
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen return TRUE;
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk }
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk return FALSE;
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk}
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volkconst char *client_get_extra_disconnect_reason(struct client *client)
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk{
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk if (ssl_require_client_cert && client->proxy != NULL) {
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk if (ssl_proxy_has_broken_client_cert(client->proxy))
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen return "(client sent an invalid cert)";
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (!ssl_proxy_has_valid_client_cert(client->proxy))
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen return "(client didn't send a cert)";
5666a3d6a7ea89362b8d9e8b39b15424cd9d6388Timo Sirainen }
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen if (client->auth_attempts == 0)
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen return "(no auth attempts)";
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen /* some auth attempts without SSL/TLS */
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen if (client->auth_tried_disabled_plaintext)
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen return "(tried to use disabled plaintext auth)";
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen if (ssl_require_client_cert)
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen return "(cert required, client didn't start TLS)";
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen
9abf5be0962538e1f6f5c73c838ff677341da0c9Timo Sirainen return t_strdup_printf("(auth failed, %u attempts)",
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen client->auth_attempts);
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen}
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen