client-common.c revision 38318f5e82662615cd88e99e398efe4a630ce020
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen/* Copyright (c) 2002-2008 Dovecot authors, see the included COPYING file */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen#include "common.h"
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen#include "hostpid.h"
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen#include "llist.h"
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen#include "str.h"
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen#include "str-sanitize.h"
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen#include "var-expand.h"
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen#include "ssl-proxy.h"
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen#include "client-common.h"
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen#include <stdlib.h>
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenstruct client *clients = NULL;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenstatic unsigned int clients_count = 0;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenvoid client_link(struct client *client)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen DLLIST_PREPEND(&clients, client);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen clients_count++;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen}
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenvoid client_unlink(struct client *client)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen i_assert(clients_count > 0);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen clients_count--;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen DLLIST_REMOVE(&clients, client);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen}
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenunsigned int clients_get_count(void)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return clients_count;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen}
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenstatic const struct var_expand_table *
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenget_var_expand_table(struct client *client)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen static struct var_expand_table static_tab[] = {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen { 'u', NULL },
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen { 'n', NULL },
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen { 'd', NULL },
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen { 's', NULL },
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen { 'h', NULL },
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen { 'l', NULL },
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen { 'r', NULL },
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen { 'p', NULL },
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen { 'm', NULL },
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen { 'a', NULL },
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen { 'b', NULL },
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen { 'c', NULL },
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen { 'k', NULL },
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen { 'e', NULL },
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen { '\0', NULL }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen };
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct var_expand_table *tab;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen unsigned int i;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen tab = t_malloc(sizeof(static_tab));
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen memcpy(tab, static_tab, sizeof(static_tab));
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (client->virtual_user != NULL) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen tab[0].value = client->virtual_user;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen tab[1].value = t_strcut(client->virtual_user, '@');
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen tab[2].value = strchr(client->virtual_user, '@');
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (tab[2].value != NULL) tab[2].value++;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen for (i = 0; i < 3; i++)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen tab[i].value = str_sanitize(tab[i].value, 80);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen tab[3].value = login_protocol;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen tab[4].value = getenv("HOME");
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen tab[5].value = net_ip2addr(&client->local_ip);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen tab[6].value = net_ip2addr(&client->ip);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen tab[7].value = my_pid;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen tab[8].value = client->auth_mech_name == NULL ? NULL :
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen str_sanitize(client->auth_mech_name, MAX_MECH_NAME);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen tab[9].value = dec2str(client->local_port);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen tab[10].value = dec2str(client->remote_port);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (!client->tls) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen tab[11].value = client->secured ? "secured" : NULL;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen tab[12].value = "";
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen } else {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen const char *ssl_state = ssl_proxy_is_handshaked(client->proxy) ?
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen "TLS" : "TLS handshaking";
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen const char *ssl_error = ssl_proxy_get_last_error(client->proxy);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen tab[11].value = ssl_error == NULL ? ssl_state :
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen t_strdup_printf("%s: %s", ssl_state, ssl_error);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen tab[12].value = ssl_proxy_get_security_string(client->proxy);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen tab[13].value = dec2str(client->mail_pid);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return tab;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen}
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenstatic bool have_key(const struct var_expand_table *table, const char *str)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen char key;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen unsigned int i;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen key = var_get_key(str);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen for (i = 0; table[i].key != '\0'; i++) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (table[i].key == key) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return table[i].value != NULL &&
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen table[i].value[0] != '\0';
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return FALSE;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen}
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenstatic void client_syslog_real(struct client *client, const char *msg)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen static struct var_expand_table static_tab[3] = {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen { 's', NULL },
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen { '$', NULL },
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen { '\0', NULL }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen };
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen const struct var_expand_table *var_expand_table;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct var_expand_table *tab;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen const char *p, *const *e;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen string_t *str;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen var_expand_table = get_var_expand_table(client);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen tab = t_malloc(sizeof(static_tab));
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen memcpy(tab, static_tab, sizeof(static_tab));
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen str = t_str_new(256);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen for (e = log_format_elements; *e != NULL; e++) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen for (p = *e; *p != '\0'; p++) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (*p != '%' || p[1] == '\0')
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen continue;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen p++;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (have_key(var_expand_table, p)) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (str_len(str) > 0)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen str_append(str, ", ");
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen var_expand(str, *e, var_expand_table);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen break;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen tab[0].value = t_strdup(str_c(str));
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen tab[1].value = msg;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen str_truncate(str, 0);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen var_expand(str, log_format, tab);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen i_info("%s", str_c(str));
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen}
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenvoid client_syslog(struct client *client, const char *msg)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen T_BEGIN {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen client_syslog_real(client, msg);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen } T_END;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen}
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenbool client_is_trusted(struct client *client)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen const char *const *net;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct ip_addr net_ip;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen unsigned int bits;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (trusted_networks == NULL)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return FALSE;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen net = t_strsplit_spaces(trusted_networks, ", ");
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen for (; *net != NULL; net++) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (net_parse_range(*net, &net_ip, &bits) < 0) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen i_error("login_trusted_networks: "
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen "Invalid network '%s'", *net);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen break;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (net_is_in_network(&client->ip, &net_ip, bits))
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return TRUE;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return FALSE;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen}
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenconst char *client_get_extra_disconnect_reason(struct client *client)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (ssl_require_client_cert && client->proxy != NULL) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (ssl_proxy_has_broken_client_cert(client->proxy))
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return "(client sent an invalid cert)";
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (!ssl_proxy_has_valid_client_cert(client->proxy))
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return "(client didn't send a cert)";
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (client->auth_attempts == 0)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return "(no auth attempts)";
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* some auth attempts without SSL/TLS */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (client->auth_tried_disabled_plaintext)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return "(tried to use disabled plaintext auth)";
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (ssl_require_client_cert)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return "(cert required, client didn't start TLS)";
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return t_strdup_printf("(auth failed, %u attempts)",
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen client->auth_attempts);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen}
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen