#define IMAP_SERVICE_NAME "imap"
-const char *client_authenticate_get_capabilities(bool secured)
+const char *client_authenticate_get_capabilities(struct imap_client *client)
{
const struct auth_mech_desc *mech;
unsigned int i, count;
c) we allow insecure authentication
*/
if ((mech[i].flags & MECH_SEC_PRIVATE) == 0 &&
- (secured || !login_settings->disable_plaintext_auth ||
+ (client->common.secured ||
+ !client->common.set->disable_plaintext_auth ||
(mech[i].flags & MECH_SEC_PLAINTEXT) == 0)) {
str_append_c(str, ' ');
str_append(str, "AUTH=");
master_user = value;
else if (strcmp(key, "user") == 0) {
/* already handled in login-common */
- } else if (login_settings->auth_debug)
+ } else if (client->common.set->auth_debug)
i_info("Ignoring unknown passdb extra field: %s", key);
}
}
if (!client->common.secured &&
- strcmp(login_settings->ssl, "required") == 0) {
- if (login_settings->verbose_auth) {
+ strcmp(client->common.set->ssl, "required") == 0) {
+ if (client->common.set->verbose_auth) {
client_syslog(&client->common, "Login failed: "
"SSL required for authentication");
}
user = IMAP_ARG_STR(&args[0]);
pass = IMAP_ARG_STR(&args[1]);
- if (!client->common.secured && login_settings->disable_plaintext_auth) {
- if (login_settings->verbose_auth) {
+ if (!client->common.secured &&
+ client->common.set->disable_plaintext_auth) {
+ if (client->common.set->verbose_auth) {
client_syslog(&client->common, "Login failed: "
"Plaintext authentication disabled");
}
#define IMAP_AUTHZ_FAILED_MSG \
"["IMAP_RESP_CODE_AUTHZFAILED"] Authorization failed"
-const char *client_authenticate_get_capabilities(bool secured);
+const char *client_authenticate_get_capabilities(struct imap_client *client);
int cmd_login(struct imap_client *client, const struct imap_arg *args);
int cmd_authenticate(struct imap_client *client, const struct imap_arg *args);
{
const char *addr;
- if (!login_settings->verbose_proctitle ||
- !login_settings->login_process_per_connection)
+ if (!client->common.set->verbose_proctitle ||
+ !client->common.set->login_process_per_connection)
return;
addr = net_ip2addr(&client->common.ip);
{
const char *auths;
- auths = client_authenticate_get_capabilities(client->common.secured);
- return t_strconcat(full ? login_settings->capability_string :
+ auths = client_authenticate_get_capabilities(client);
+ return t_strconcat(full ? client->common.set->capability_string :
CAPABILITY_BANNER_STRING,
(ssl_initialized && !client->common.tls) ?
" STARTTLS" : "",
- login_settings->disable_plaintext_auth &&
+ client->common.set->disable_plaintext_auth &&
!client->common.secured ?
" LOGINDISABLED" : "", auths, NULL);
}
return;
fd_ssl = ssl_proxy_new(client->common.fd, &client->common.ip,
- &client->common.proxy);
+ client->common.set, &client->common.proxy);
if (fd_ssl == -1) {
client_send_line(client, "* BYE TLS initialization failed.");
client_destroy(client,
void client_destroy_oldest(void)
{
- unsigned int max_connections = login_settings->login_max_connections;
+ unsigned int max_connections =
+ global_login_settings->login_max_connections;
struct client *client;
struct imap_client *destroy_buf[CLIENT_DESTROY_OLDEST_COUNT];
unsigned int i, destroy_count;
greet = t_str_new(128);
str_append(greet, "* OK ");
str_printfa(greet, "[CAPABILITY %s] ", get_capability(client, FALSE));
- str_append(greet, login_settings->login_greeting);
+ str_append(greet, client->common.set->login_greeting);
client_send_line(client, str_c(greet));
client->greeting_sent = TRUE;
client_auth_waiting_timeout, client);
}
-struct client *client_create(int fd, bool ssl, const struct ip_addr *local_ip,
- const struct ip_addr *ip)
+struct client *client_create(int fd, bool ssl, pool_t pool,
+ const struct login_settings *set,
+ const struct ip_addr *local_ip,
+ const struct ip_addr *remote_ip)
{
struct imap_client *client;
i_assert(fd != -1);
- if (clients_get_count() >= login_settings->login_max_connections) {
+ if (clients_get_count() >= set->login_max_connections) {
/* reached max. users count, kill few of the
oldest connections */
client_destroy_oldest();
/* always use nonblocking I/O */
net_set_nonblock(fd, TRUE);
- client = i_new(struct imap_client, 1);
+ client = p_new(pool, struct imap_client, 1);
client->created = ioloop_time;
client->refcount = 1;
+ client->common.pool = pool;
+ client->common.set = set;
client->common.local_ip = *local_ip;
- client->common.ip = *ip;
+ client->common.ip = *remote_ip;
client->common.fd = fd;
client->common.tls = ssl;
client->common.trusted = client_is_trusted(&client->common);
client->common.secured = ssl || client->common.trusted ||
- net_ip_compare(ip, local_ip);
+ net_ip_compare(remote_ip, local_ip);
client_open_streams(client, fd);
client->io = io_add(fd, IO_READ, client_input, client);
backend_capabilities =
capabilities_strip_prelogin(t_strsplit(capability, " "));
proxy_capabilities =
- capabilities_strip_prelogin(t_strsplit(login_settings->capability_string, " "));
+ capabilities_strip_prelogin(t_strsplit(client->common.set->capability_string, " "));
if (str_array_icmp(backend_capabilities, proxy_capabilities))
return;
return 1;
} else if (strncmp(line, "L ", 2) == 0) {
line += 2;
- if (login_settings->verbose_auth) {
+ if (client->common.set->verbose_auth) {
str = t_str_new(128);
str_printfa(str, "proxy(%s): Login failed to %s:%u",
client->common.virtual_user,
tab[12].value = ssl_proxy_get_security_string(client->proxy);
}
tab[13].value = dec2str(client->mail_pid);
-
return tab;
}
};
const struct var_expand_table *var_expand_table;
struct var_expand_table *tab;
- const char *p, *const *e;
+ const char *p;
+ char *const *e;
string_t *str;
var_expand_table = get_var_expand_table(client);
memcpy(tab, static_tab, sizeof(static_tab));
str = t_str_new(256);
- for (e = login_settings->log_format_elements_split; *e != NULL; e++) {
+ for (e = client->set->log_format_elements_split; *e != NULL; e++) {
for (p = *e; *p != '\0'; p++) {
if (*p != '%' || p[1] == '\0')
continue;
tab[1].value = msg;
str_truncate(str, 0);
- var_expand(str, login_settings->login_log_format, tab);
+ var_expand(str, client->set->login_log_format, tab);
return str_c(str);
}
struct ip_addr net_ip;
unsigned int bits;
- if (login_settings->login_trusted_networks == NULL)
+ if (client->set->login_trusted_networks == NULL)
return FALSE;
- net = t_strsplit_spaces(login_settings->login_trusted_networks, ", ");
+ net = t_strsplit_spaces(client->set->login_trusted_networks, ", ");
for (; *net != NULL; net++) {
if (net_parse_range(*net, &net_ip, &bits) < 0) {
i_error("login_trusted_networks: "
const char *client_get_extra_disconnect_reason(struct client *client)
{
- if (login_settings->ssl_require_client_cert && client->proxy != NULL) {
+ if (client->set->ssl_require_client_cert && client->proxy != NULL) {
if (ssl_proxy_has_broken_client_cert(client->proxy))
return "(client sent an invalid cert)";
if (!ssl_proxy_has_valid_client_cert(client->proxy))
/* some auth attempts without SSL/TLS */
if (client->auth_tried_disabled_plaintext)
return "(tried to use disabled plaintext auth)";
- if (login_settings->ssl_require_client_cert)
+ if (client->set->ssl_require_client_cert)
return "(cert required, client didn't start TLS)";
return t_strdup_printf("(auth failed, %u attempts)",
struct client {
struct client *prev, *next;
+ pool_t pool;
struct ip_addr local_ip;
struct ip_addr ip;
unsigned int local_port, remote_port;
struct ssl_proxy *proxy;
+ const struct login_settings *set;
int fd;
struct istream *input;
extern struct client *clients;
-struct client *client_create(int fd, bool ssl, const struct ip_addr *local_ip,
- const struct ip_addr *ip);
+struct client *client_create(int fd, bool ssl, pool_t pool,
+ const struct login_settings *set,
+ const struct ip_addr *local_ip,
+ const struct ip_addr *remote_ip);
void client_link(struct client *client);
void client_unlink(struct client *client);
extern int anvil_fd;
extern struct master_service *service;
-extern struct login_settings *login_settings;
+extern const struct login_settings *global_login_settings;
#endif
io_remove(&proxy->server_io);
fd = ssl_proxy_client_new(proxy->server_fd, &proxy->ip,
+ proxy->prelogin_client->set,
login_proxy_ssl_handshaked, proxy,
&proxy->ssl_proxy);
if (fd < 0) {
static struct login_settings login_default_settings = {
MEMBER(login_chroot) TRUE,
MEMBER(login_trusted_networks) "",
- MEMBER(login_greeting) PACKAGE" ready.",
+ MEMBER(login_greeting) PACKAGE_NAME" ready.",
MEMBER(login_log_format_elements) "user=<%u> method=%m rip=%r lip=%l %c",
MEMBER(login_log_format) "%$: %s",
#endif
}
-static bool login_settings_check(void *_set, pool_t pool ATTR_UNUSED,
- const char **error_r)
+static bool login_settings_check(void *_set, pool_t pool, const char **error_r)
{
struct login_settings *set = _set;
set->log_format_elements_split =
- t_strsplit(set->login_log_format_elements, " ");
+ p_strsplit(pool, set->login_log_format_elements, " ");
if (set->ssl_require_client_cert || set->ssl_username_from_cert) {
/* if we require valid cert, make sure we also ask for it */
}
/* </settings checks> */
-struct login_settings *login_settings_read(struct master_service *service)
+struct login_settings *
+login_settings_read(struct master_service *service, pool_t pool,
+ const struct ip_addr *local_ip,
+ const struct ip_addr *remote_ip)
{
static const struct setting_parser_info *set_roots[] = {
&login_setting_parser_info,
struct master_service_settings_input input;
const char *error;
void **sets;
+ struct login_settings *set;
memset(&input, 0, sizeof(input));
input.roots = set_roots;
input.module = "login";
input.service = login_protocol;
+ if (local_ip != NULL)
+ input.local_ip = *local_ip;
+ if (remote_ip != NULL)
+ input.remote_ip = *remote_ip;
+
+ /* this function always clears the previous settings pool. since we're
+ doing per-connection lookups, we always need to duplicate the
+ settings using another pool. */
if (master_service_settings_read(service, &input, &error) < 0)
i_fatal("Error reading configuration: %s", error);
sets = master_service_settings_get_others(service);
- return sets[0];
+ set = settings_dup(&login_setting_parser_info, sets[0], pool);
+ if (!login_settings_check(set, pool, &error))
+ i_fatal("login_settings_check() failed: %s", error);
+ return set;
}
unsigned int mail_max_userip_connections;
/* generated: */
- const char *const *log_format_elements_split;
+ char *const *log_format_elements_split;
};
-struct login_settings *login_settings_read(struct master_service *service);
+struct login_settings *
+login_settings_read(struct master_service *service, pool_t pool,
+ const struct ip_addr *local_ip,
+ const struct ip_addr *remote_ip);
#endif
int anvil_fd = -1;
struct master_service *service;
-struct login_settings *login_settings;
+const struct login_settings *global_login_settings;
static bool ssl_connections = FALSE;
struct client *client;
struct ssl_proxy *proxy;
struct ip_addr local_ip;
+ const struct login_settings *set;
unsigned int local_port;
+ pool_t pool;
int fd_ssl;
if (net_getsockname(conn->fd, &local_ip, &local_port) < 0) {
local_port = 0;
}
+ pool = pool_alloconly_create("login client", 1024);
+ set = login_settings_read(service, pool, &local_ip, &conn->remote_ip);
+
if (!ssl_connections && !conn->ssl) {
- client = client_create(conn->fd, FALSE, &local_ip,
+ client = client_create(conn->fd, FALSE, pool, set, &local_ip,
&conn->remote_ip);
} else {
- fd_ssl = ssl_proxy_new(conn->fd, &conn->remote_ip, &proxy);
+ fd_ssl = ssl_proxy_new(conn->fd, &conn->remote_ip, set, &proxy);
if (fd_ssl == -1) {
net_disconnect(conn->fd);
+ pool_unref(&pool);
return;
}
- client = client_create(fd_ssl, TRUE,
+ client = client_create(fd_ssl, TRUE, pool, set,
&local_ip, &conn->remote_ip);
client->proxying = TRUE;
client->proxy = proxy;
}
+
client->remote_port = conn->remote_port;
client->local_port = local_port;
}
normal connections each use one fd, but SSL connections use two */
max_fds = MASTER_LISTEN_FD_FIRST + 16 +
master_service_get_socket_count(service) +
- login_settings->login_max_connections*2;
+ global_login_settings->login_max_connections*2;
restrict_fd_limit(max_fds);
io_loop_set_max_fd_count(current_ioloop, max_fds);
- i_assert(strcmp(login_settings->ssl, "no") == 0 || ssl_initialized);
+ i_assert(strcmp(global_login_settings->ssl, "no") == 0 ||
+ ssl_initialized);
- if (login_settings->mail_max_userip_connections > 0)
+ if (global_login_settings->mail_max_userip_connections > 0)
anvil_fd = anvil_connect();
restrict_access_by_env(NULL, TRUE);
int main(int argc, char *argv[], char *envp[])
{
const char *getopt_str;
+ pool_t set_pool;
int c;
//FIXME:is_inetd = getenv("DOVECOT_MASTER") == NULL;
- service = master_service_init(login_process_name, 0, argc, argv);
+ service = master_service_init(login_process_name,
+ MASTER_SERVICE_FLAG_KEEP_CONFIG_OPEN,
+ argc, argv);
master_service_init_log(service, t_strconcat(login_process_name, ": ",
NULL), 0);
#endif
process_title_init(argv, envp);
- login_settings = login_settings_read(service);
+ set_pool = pool_alloconly_create("global login settings", 1024);
+ global_login_settings =
+ login_settings_read(service, set_pool, NULL, NULL);
main_preinit();
master_service_init_finish(service);
master_service_run(service, client_connected);
main_deinit();
+ pool_unref(&set_pool);
master_service_deinit(&service);
return 0;
}
if (client->virtual_user == NULL)
return FALSE;
- if (login_settings->mail_max_userip_connections == 0)
+ if (client->set->mail_max_userip_connections == 0)
return FALSE;
ident = t_strconcat("LOOKUP\t", net_ip2addr(&client->ip), "/",
buf[ret-1] = '\0';
return strtoul(buf, NULL, 10) >=
- login_settings->mail_max_userip_connections;
+ client->set->mail_max_userip_connections;
}
static void authenticate_callback(struct auth_request *request, int status,
return;
}
- if (!client->secured && login_settings->disable_plaintext_auth &&
+ if (!client->secured && client->set->disable_plaintext_auth &&
(mech->flags & MECH_SEC_PLAINTEXT) != 0) {
sasl_server_auth_failed(client,
"Plaintext authentication disabled.");
{
i_assert(client->authenticating);
- if (login_settings->verbose_auth && reason != NULL) {
+ if (client->set->verbose_auth && reason != NULL) {
const char *auth_name =
str_sanitize(client->auth_mech_name, MAX_MECH_NAME);
client_syslog(client,
SSL *ssl;
struct ip_addr ip;
+ const struct login_settings *set;
int fd_ssl, fd_plain;
struct io *io_ssl_read, *io_ssl_write, *io_plain_read, *io_plain_write;
static int
ssl_proxy_new_common(SSL_CTX *ssl_ctx, int fd, const struct ip_addr *ip,
+ const struct login_settings *set,
struct ssl_proxy **proxy_r)
{
struct ssl_proxy *proxy;
proxy = i_new(struct ssl_proxy, 1);
proxy->refcount = 2;
proxy->ssl = ssl;
+ proxy->set = set;
proxy->fd_ssl = fd;
proxy->fd_plain = sfd[0];
proxy->ip = *ip;
return sfd[1];
}
-int ssl_proxy_new(int fd, const struct ip_addr *ip, struct ssl_proxy **proxy_r)
+int ssl_proxy_new(int fd, const struct ip_addr *ip,
+ const struct login_settings *set, struct ssl_proxy **proxy_r)
{
int ret;
- if ((ret = ssl_proxy_new_common(ssl_server_ctx, fd, ip, proxy_r)) < 0)
+ ret = ssl_proxy_new_common(ssl_server_ctx, fd, ip, set, proxy_r);
+ if (ret < 0)
return -1;
ssl_step(*proxy_r);
}
int ssl_proxy_client_new(int fd, struct ip_addr *ip,
+ const struct login_settings *set,
ssl_handshake_callback_t *callback, void *context,
struct ssl_proxy **proxy_r)
{
int ret;
- if ((ret = ssl_proxy_new_common(ssl_client_ctx, fd, ip, proxy_r)) < 0)
+ ret = ssl_proxy_new_common(ssl_client_ctx, fd, ip, set, proxy_r);
+ if (ret < 0)
return -1;
(*proxy_r)->handshake_callback = callback;
proxy = SSL_get_ex_data(ssl, extdata_index);
proxy->cert_received = TRUE;
- if (login_settings->verbose_ssl ||
- (login_settings->verbose_auth && !preverify_ok)) {
+ if (proxy->set->verbose_ssl ||
+ (proxy->set->verbose_auth && !preverify_ok)) {
char buf[1024];
X509_NAME *subject;
void ssl_proxy_init(void)
{
- const struct login_settings *set = login_settings;
+ const struct login_settings *set = global_login_settings;
static char dovecot[] = "dovecot";
unsigned char buf;
struct ip_addr;
struct ssl_proxy;
+struct login_settings;
extern bool ssl_initialized;
/* establish SSL connection with the given fd, returns a new fd which you
must use from now on, or -1 if error occurred. Unless -1 is returned,
the given fd must be simply forgotten. */
-int ssl_proxy_new(int fd, const struct ip_addr *ip, struct ssl_proxy **proxy_r);
+int ssl_proxy_new(int fd, const struct ip_addr *ip,
+ const struct login_settings *set, struct ssl_proxy **proxy_r);
int ssl_proxy_client_new(int fd, struct ip_addr *ip,
+ const struct login_settings *set,
ssl_handshake_callback_t *callback, void *context,
struct ssl_proxy **proxy_r);
bool ssl_proxy_has_valid_client_cert(const struct ssl_proxy *proxy) ATTR_PURE;
if (ssl_initialized && !client->common.tls)
str_append(str, "STLS\r\n");
- if (!login_settings->disable_plaintext_auth || client->common.secured)
+ if (!client->common.set->disable_plaintext_auth ||
+ client->common.secured)
str_append(str, "USER\r\n");
str_append(str, "SASL");
*/
if ((mech[i].flags & MECH_SEC_PRIVATE) == 0 &&
(client->common.secured ||
- !login_settings->disable_plaintext_auth ||
+ !client->common.set->disable_plaintext_auth ||
(mech[i].flags & MECH_SEC_PLAINTEXT) == 0)) {
str_append_c(str, ' ');
str_append(str, mech[i].name);
master_user = value;
else if (strcmp(key, "user") == 0) {
/* already handled in login-common */
- } else if (login_settings->auth_debug)
+ } else if (client->common.set->auth_debug)
i_info("Ignoring unknown passdb extra field: %s", key);
}
const char *mech_name, *p;
if (!client->common.secured &&
- strcmp(login_settings->ssl, "required") == 0) {
- if (login_settings->verbose_auth) {
+ strcmp(client->common.set->ssl, "required") == 0) {
+ if (client->common.set->verbose_auth) {
client_syslog(&client->common, "Login failed: "
"SSL required for authentication");
}
for (i = 0; i < count; i++) {
if ((mech[i].flags & MECH_SEC_PRIVATE) == 0 &&
(client->common.secured ||
- login_settings->disable_plaintext_auth ||
+ client->common.set->disable_plaintext_auth ||
(mech[i].flags & MECH_SEC_PLAINTEXT) == 0))
client_send_line(client, mech[i].name);
}
static bool check_plaintext_auth(struct pop3_client *client)
{
if (client->common.secured ||
- !login_settings->disable_plaintext_auth)
+ !client->common.set->disable_plaintext_auth)
return TRUE;
- if (login_settings->verbose_auth) {
+ if (client->common.set->verbose_auth) {
client_syslog(&client->common, "Login failed: "
"Plaintext authentication disabled");
}
const char *p;
if (client->apop_challenge == NULL) {
- if (login_settings->verbose_auth) {
+ if (client->common.set->verbose_auth) {
client_syslog(&client->common,
"APOP failed: APOP not enabled");
}
/* <username> <md5 sum in hex> */
p = strchr(args, ' ');
if (p == NULL || strlen(p+1) != 32) {
- if (login_settings->verbose_auth) {
+ if (client->common.set->verbose_auth) {
client_syslog(&client->common,
"APOP failed: Invalid parameters");
}
buffer_append_c(apop_data, '\0');
if (hex_to_binary(p+1, apop_data) < 0) {
- if (login_settings->verbose_auth) {
+ if (client->common.set->verbose_auth) {
client_syslog(&client->common, "APOP failed: "
"Invalid characters in MD5 response");
}
{
const char *addr;
- if (!login_settings->verbose_proctitle ||
- !login_settings->login_process_per_connection)
+ if (!client->common.set->verbose_proctitle ||
+ !client->common.set->login_process_per_connection)
return;
addr = net_ip2addr(&client->common.ip);
return;
fd_ssl = ssl_proxy_new(client->common.fd, &client->common.ip,
- &client->common.proxy);
+ client->common.set, &client->common.proxy);
if (fd_ssl == -1) {
client_send_line(client, "-ERR TLS initialization failed.");
client_destroy(client,
void client_destroy_oldest(void)
{
- unsigned int max_connections = login_settings->login_max_connections;
+ unsigned int max_connections =
+ global_login_settings->login_max_connections;
struct client *client;
struct pop3_client *destroy_buf[CLIENT_DESTROY_OLDEST_COUNT];
unsigned int i, destroy_count;
client->apop_challenge = get_apop_challenge(client);
client_send_line(client, t_strconcat("+OK ",
- login_settings->login_greeting,
+ client->common.set->login_greeting,
client->apop_challenge != NULL ?
" " : NULL,
client->apop_challenge, NULL));
client_destroy(client, "Disconnected: Inactivity");
}
-struct client *client_create(int fd, bool ssl, const struct ip_addr *local_ip,
- const struct ip_addr *ip)
+struct client *client_create(int fd, bool ssl, pool_t pool,
+ const struct login_settings *set,
+ const struct ip_addr *local_ip,
+ const struct ip_addr *remote_ip)
{
struct pop3_client *client;
i_assert(fd != -1);
- if (clients_get_count() >= login_settings->login_max_connections) {
+ if (clients_get_count() >= set->login_max_connections) {
/* reached max. users count, kill few of the
oldest connections */
client_destroy_oldest();
/* always use nonblocking I/O */
net_set_nonblock(fd, TRUE);
- client = i_new(struct pop3_client, 1);
+ client = p_new(pool, struct pop3_client, 1);
client->created = ioloop_time;
client->refcount = 1;
+ client->common.pool = pool;
+ client->common.set = set;
client->common.local_ip = *local_ip;
- client->common.ip = *ip;
+ client->common.ip = *remote_ip;
client->common.fd = fd;
client->common.tls = ssl;
client->common.trusted = client_is_trusted(&client->common);
client->common.secured = ssl || client->common.trusted ||
- net_ip_compare(ip, local_ip);
+ net_ip_compare(remote_ip, local_ip);
client_open_streams(client, fd);
client_link(&client->common);
else
client_send_line(client, line);
- if (login_settings->verbose_auth) {
+ if (client->common.set->verbose_auth) {
str = t_str_new(128);
str_printfa(str, "proxy(%s): Login failed to %s:%u",
client->common.virtual_user,