#include "doveadm-settings.h"
#include "doveadm-mail.h"
#include "doveadm-print.h"
-#include "doveadm-server.h"
#include "client-connection.h"
#include "server-connection.h"
#include "dsync/dsync-brain.h"
const struct master_service_ssl_settings *ssl_set,
const char *target, bool ssl, const char **error_r)
{
- struct doveadm_server *server;
+ struct doveadm_client_settings conn_set;
struct server_connection *conn;
struct ioloop *prev_ioloop, *ioloop;
const char *p, *error;
- server = p_new(ctx->ctx.pool, struct doveadm_server, 1);
- server->name = p_strdup(ctx->ctx.pool, target);
- p = strrchr(server->name, ':');
- server->hostname = p == NULL ? server->name :
- p_strdup_until(ctx->ctx.pool, server->name, p);
- if (p == NULL)
- server->port = doveadm_settings->doveadm_port;
- else if (net_str2port(p+1, &server->port) < 0) {
- *error_r = t_strdup_printf("Invalid port number: %s", p+1);
- return -1;
+ i_zero(&conn_set);
+ if (strchr(target, '/') != NULL)
+ conn_set.socket_path = target;
+ else {
+ p = strrchr(target, ':');
+ conn_set.hostname = p == NULL ? target :
+ p_strdup_until(ctx->ctx.pool, target, p);
+ if (p == NULL)
+ conn_set.port = doveadm_settings->doveadm_port;
+ else if (net_str2port(p+1, &conn_set.port) < 0) {
+ *error_r = t_strdup_printf("Invalid port number: %s", p+1);
+ return -1;
+ }
}
if (ssl) {
"Couldn't initialize SSL context: %s", error);
return -1;
}
- server->ssl_flags = AUTH_PROXY_SSL_FLAG_YES;
- server->ssl_ctx = ctx->ssl_ctx;
+ conn_set.ssl_flags = AUTH_PROXY_SSL_FLAG_YES;
+ conn_set.ssl_ctx = ctx->ssl_ctx;
}
- server->username = p_strdup(ctx->ctx.pool,
- ctx->ctx.set->doveadm_username);
- server->password = p_strdup(ctx->ctx.pool,
- ctx->ctx.set->doveadm_password);
+ conn_set.username = ctx->ctx.set->doveadm_username;
+ conn_set.password = ctx->ctx.set->doveadm_password;
prev_ioloop = current_ioloop;
ioloop = io_loop_create();
if (doveadm_verbose_proctitle) {
process_title_set(t_strdup_printf(
- "[dsync - connecting to %s]", server->name));
+ "[dsync - connecting to %s]", target));
}
- if (server_connection_create(server, &conn, &error) < 0) {
+ if (server_connection_create(&conn_set, &conn, &error) < 0) {
ctx->error = p_strdup_printf(ctx->ctx.pool,
"Couldn't create server connection: %s", error);
} else {
if (doveadm_verbose_proctitle) {
process_title_set(t_strdup_printf(
- "[dsync - running dsync-server on %s]", server->name));
+ "[dsync - running dsync-server on %s]", target));
}
dsync_server_run_command(ctx, conn);
};
struct doveadm_server_request {
+ pool_t pool;
struct doveadm_server *server;
- char *username;
+ struct doveadm_client_settings set;
+ const char *username;
};
static HASH_TABLE(char *, struct doveadm_server *) servers;
static void doveadm_server_request_free(struct doveadm_server_request *request)
{
- i_free(request->username);
+ ssl_iostream_context_unref(&request->set.ssl_ctx);
+ pool_unref(&request->pool);
}
static struct doveadm_server *doveadm_server_get(const char *name)
{
struct doveadm_server *server;
- const char *p;
char *dup_name;
if (!hash_table_is_created(servers)) {
if (server == NULL) {
server = p_new(server_pool, struct doveadm_server, 1);
server->name = dup_name = p_strdup(server_pool, name);
- server->username = p_strdup(server_pool,
- doveadm_settings->doveadm_username);
- server->password = p_strdup(server_pool,
- doveadm_settings->doveadm_password);
- p = strrchr(server->name, ':');
- server->hostname = p == NULL ? server->name :
- p_strdup_until(server_pool, server->name, p);
hash_table_insert(servers, dup_name, server);
}
server_name = t_strdup_printf("%s:%u", net_ip2addr(ip), port);
new_server = doveadm_server_get(server_name);
- new_server->ip = *ip;
- new_server->ssl_flags = ssl_flags;
- new_server->port = port;
- if (server_connection_create(new_server, &conn, &error) < 0) {
+ struct doveadm_client_settings conn_set = {
+ .hostname = net_ip2addr(ip),
+ .ip = *ip,
+ .port = port,
+ .username = doveadm_settings->doveadm_username,
+ .password = doveadm_settings->doveadm_password,
+ .ssl_flags = ssl_flags,
+ .log_passthrough = TRUE,
+ };
+
+ if (server_connection_create(&conn_set, &conn, &error) < 0) {
*error_r = t_strdup_printf(
"Failed to create redirect connection to %s: %s",
new_server->name, error);
}
servercmd->conn = conn;
+ servercmd->server = new_server;
if (servercmd->input != NULL)
i_stream_seek(servercmd->input, 0);
server_connection_cmd(conn, servercmd->proxy_ttl,
const char *destination)
{
struct doveadm_server *orig_server = servercmd->server;
+ const struct doveadm_client_settings *client_set =
+ server_connection_get_settings(servercmd->conn);
struct ip_addr ip;
in_port_t port;
const char *destuser, *host, *error;
return -1;
}
if (port == 0)
- port = orig_server->port;
+ port = client_set->port;
if (cmd_ctx->cctx->proxy_redirect_reauth) {
ret = doveadm_cmd_redirect_relookup(servercmd, &ip, port,
destuser, &error);
} else {
ret = doveadm_cmd_redirect_finish(servercmd, &ip, port,
- orig_server->ssl_flags,
+ client_set->ssl_flags,
&error);
}
if (ret < 0) {
request_copy = *request;
array_pop_front(&doveadm_server_request_queue);
- if (server_connection_create(request_copy.server, &conn, error_r) < 0) {
+ if (server_connection_create(&request_copy.set, &conn, error_r) < 0) {
internal_failure = TRUE;
return -1;
}
so undo any sticks we might have added already */
doveadm_print_unstick_headers();
+ struct doveadm_client_settings conn_set = {
+ .socket_path = socket_path,
+ .hostname = proxy_set.host,
+ .ip = proxy_set.host_ip,
+ .port = proxy_set.port,
+ .username = ctx->set->doveadm_username,
+ .password = ctx->set->doveadm_password,
+ .ssl_flags = proxy_set.ssl_flags,
+ };
+
server_name = socket_path != NULL ? socket_path :
t_strdup_printf("%s:%u", proxy_set.host, proxy_set.port);
server = doveadm_server_get(server_name);
- server->ip = proxy_set.host_ip;
- server->ssl_flags = proxy_set.ssl_flags;
- server->port = proxy_set.port;
unsigned int limit = I_MAX(ctx->set->doveadm_worker_count, 1);
/* Make sure there's space for the new request. Either by creating a
}
if (server_connections_count() <= limit) {
- if (server_connection_create(server, &conn, error_r) < 0) {
+ if (server_connection_create(&conn_set, &conn, error_r) < 0) {
internal_failure = TRUE;
return -1;
} else {
}
} else {
request = array_append_space(&doveadm_server_request_queue);
- request->username = i_strdup(proxy_set.username);
+ request->pool = pool_alloconly_create("doveadm server request", 256);
request->server = server;
+ request->username = p_strdup(request->pool, proxy_set.username);
+ doveadm_client_settings_dup(&conn_set, &request->set, request->pool);
}
*error_r = "doveadm server failure";
return DOVEADM_MAIL_SERVER_FAILED() ? -1 : 1;
}
-static void doveadm_servers_destroy_all_connections(void)
-{
- struct hash_iterate_context *iter;
- char *key;
- struct doveadm_server *server;
-
- iter = hash_table_iterate_init(servers);
- while (hash_table_iterate(iter, servers, &key, &server))
- ssl_iostream_context_unref(&server->ssl_ctx);
- hash_table_iterate_deinit(&iter);
-
- server_connections_destroy_all();
-}
-
void doveadm_mail_server_flush(void)
{
struct doveadm_server_request *request;
server_connections_count() > 0)
io_loop_run(current_ioloop);
- doveadm_servers_destroy_all_connections();
+ server_connections_destroy_all();
if (master_service_is_killed(master_service))
i_error("Aborted");
if (DOVEADM_MAIL_SERVER_FAILED())
struct doveadm_server {
/* hostname:port or UNIX socket path. Used mainly for logging. */
const char *name;
- /* If this contains '/', it's a UNIX socket path. Otherwise it's
- the hostname without port. */
- const char *hostname;
- /* Host's IP to use, if known. Otherwise DNS lookup is done. */
- struct ip_addr ip;
- /* Port to use for TCP connections. */
- in_port_t port;
-
- const char *username, *password;
-
- /* ssl related settings */
- enum auth_proxy_ssl_flags ssl_flags;
- struct ssl_iostream_context *ssl_ctx;
};
#endif
struct server_connection {
struct connection conn;
- struct doveadm_server *server;
+
+ struct doveadm_client_settings set;
pool_t pool;
struct timeout *to_destroy;
const char **error_r);
static void server_connection_destroy(struct server_connection **_conn);
+void doveadm_client_settings_dup(const struct doveadm_client_settings *src,
+ struct doveadm_client_settings *dest_r,
+ pool_t pool)
+{
+ i_zero(dest_r);
+
+ dest_r->socket_path = p_strdup(pool, src->socket_path);
+ dest_r->hostname = p_strdup(pool, src->hostname);
+ dest_r->ip = src->ip;
+ dest_r->port = src->port;
+
+ dest_r->username = p_strdup(pool, src->username);
+ dest_r->password = p_strdup(pool, src->password);
+
+ dest_r->ssl_flags = src->ssl_flags;
+ if (src->ssl_ctx != NULL) {
+ dest_r->ssl_ctx = src->ssl_ctx;
+ ssl_iostream_context_ref(dest_r->ssl_ctx);
+ }
+}
+
static void server_set_print_pending(struct server_connection *conn)
{
if (!array_is_created(&print_pending_connections))
string_t *plain = t_str_new(128);
string_t *cmd = t_str_new(128);
- if (*conn->server->password == '\0') {
+ if (*conn->set.password == '\0') {
e_error(conn->conn.event, "doveadm_password not set, "
"can't authenticate to remote server");
return -1;
}
str_append_c(plain, '\0');
- str_append(plain, conn->server->username);
+ str_append(plain, conn->set.username);
str_append_c(plain, '\0');
- str_append(plain, conn->server->password);
+ str_append(plain, conn->set.password);
str_append(cmd, "PLAIN\t");
base64_encode(plain->data, plain->used, cmd);
"Doveadm server sent invalid log type 0x%02x",
line[0]);
line++;
- i_log_type(&ctx, "remote(%s): %s", conn->server->name, line);
+ i_log_type(&ctx, "remote(%s): %s", conn->conn.name, line);
}
}
return;
}
if (!conn->ssl_done &&
- (conn->server->ssl_flags & AUTH_PROXY_SSL_FLAG_STARTTLS) != 0) {
+ (conn->set.ssl_flags & AUTH_PROXY_SSL_FLAG_STARTTLS) != 0) {
connection_input_halt(&conn->conn);
if (conn->conn.minor_version < DOVEADM_PROTO_MINOR_MIN_STARTTLS) {
e_error(conn->conn.event,
struct ssl_iostream_settings ssl_set;
const char *error;
- if (conn->server->ssl_flags == 0)
+ if (conn->set.ssl_flags == 0)
return 0;
doveadm_get_ssl_settings(&ssl_set, pool_datastack_create());
- if ((conn->server->ssl_flags & AUTH_PROXY_SSL_FLAG_ANY_CERT) != 0)
+ if ((conn->set.ssl_flags & AUTH_PROXY_SSL_FLAG_ANY_CERT) != 0)
ssl_set.allow_invalid_cert = TRUE;
if (ssl_set.allow_invalid_cert)
ssl_set.verbose_invalid_cert = TRUE;
- if (conn->server->ssl_ctx == NULL &&
- ssl_iostream_client_context_cache_get(&ssl_set,
- &conn->server->ssl_ctx,
+ if (conn->set.ssl_ctx == NULL &&
+ ssl_iostream_client_context_cache_get(&ssl_set, &conn->set.ssl_ctx,
&error) < 0) {
*error_r = t_strdup_printf(
"Couldn't initialize SSL client: %s", error);
return -1;
}
+ const char *hostname =
+ conn->set.hostname != NULL ? conn->set.hostname : "";
connection_input_halt(&conn->conn);
- if (io_stream_create_ssl_client(conn->server->ssl_ctx,
- conn->server->hostname, &ssl_set,
+ if (io_stream_create_ssl_client(conn->set.ssl_ctx, hostname, &ssl_set,
&conn->conn.input, &conn->conn.output,
&conn->ssl_iostream, &error) < 0) {
*error_r = t_strdup_printf(
server_connection_output, conn);
connection_input_halt(&conn->conn);
- if (((conn->server->ssl_flags & AUTH_PROXY_SSL_FLAG_STARTTLS) == 0 &&
+ if (((conn->set.ssl_flags & AUTH_PROXY_SSL_FLAG_STARTTLS) == 0 &&
server_connection_init_ssl(conn, &error) < 0)) {
e_error(conn->conn.event, "%s", error);
/* Can't safely destroy the connection here, so delay it */
.client_connect_timeout_msecs = DOVEADM_TCP_CONNECT_TIMEOUT_SECS,
};
-int server_connection_create(struct doveadm_server *server,
+int server_connection_create(const struct doveadm_client_settings *set,
struct server_connection **conn_r,
const char **error_r)
{
pool_t pool;
int ret;
- i_assert(server->username != NULL);
- i_assert(server->password != NULL);
+ i_assert(set->username != NULL);
+ i_assert(set->password != NULL);
if (doveadm_clients == NULL) {
doveadm_clients =
pool = pool_alloconly_create("doveadm server connection", 1024*16);
conn = p_new(pool, struct server_connection, 1);
conn->pool = pool;
- conn->server = server;
- if (strchr(server->hostname, '/') != NULL) {
+ doveadm_client_settings_dup(set, &conn->set, pool);
+
+ if (set->socket_path != NULL) {
connection_init_client_unix(doveadm_clients, &conn->conn,
- server->hostname);
- } else if (server->ip.family != 0) {
+ set->socket_path);
+ } else if (set->ip.family != 0) {
connection_init_client_ip(doveadm_clients, &conn->conn,
- server->hostname, &server->ip,
- server->port);
+ set->hostname, &set->ip, set->port);
} else {
struct ip_addr *ips;
unsigned int ips_count;
- ret = net_gethostbyname(server->hostname, &ips, &ips_count);
+ ret = net_gethostbyname(set->hostname, &ips, &ips_count);
if (ret != 0) {
*error_r = t_strdup_printf(
"Lookup of host %s failed: %s",
- server->hostname, net_gethosterror(ret));
+ set->hostname, net_gethosterror(ret));
pool_unref(&pool);
return -1;
}
connection_init_client_ip(doveadm_clients, &conn->conn,
- server->hostname, &ips[0],
- server->port);
+ set->hostname, &ips[0], set->port);
}
if (connection_client_connect(&conn->conn) < 0) {
*error_r = t_strdup_printf(
- "net_connect(%s) failed: %m", server->name);
+ "net_connect(%s) failed: %m", conn->conn.name);
connection_deinit(&conn->conn);
pool_unref(&pool);
return -1;
timeout_remove(&conn->to_destroy);
connection_deinit(&conn->conn);
+ ssl_iostream_context_unref(&conn->set.ssl_ctx);
pool_unref(&conn->pool);
}
}
}
+const struct doveadm_client_settings *
+server_connection_get_settings(struct server_connection *conn)
+{
+ return &conn->set;
+}
+
void server_connection_cmd(struct server_connection *conn, int proxy_ttl,
const char *line, struct istream *cmd_input,
server_cmd_callback_t *callback, void *context)
#ifndef SERVER_CONNECTION_H
#define SERVER_CONNECTION_H
+#include "doveadm-server.h"
+
#define SERVER_EXIT_CODE_DISCONNECTED 1000
-struct doveadm_server;
struct server_connection;
struct ssl_iostream;
size_t size, bool finished,
void *context);
-int server_connection_create(struct doveadm_server *server,
+struct doveadm_client_settings {
+ /* UNIX socket path to connect to, if non-NULL. */
+ const char *socket_path;
+
+ /* Hostname to connect to, if UNIX socket path wasn't specified. */
+ const char *hostname;
+ /* Host's IP to use, if known. Otherwise DNS lookup is done. */
+ struct ip_addr ip;
+ /* Port to use for TCP connections. */
+ in_port_t port;
+
+ /* Username and password for authentication */
+ const char *username, *password;
+
+ /* SSL flags. */
+ enum auth_proxy_ssl_flags ssl_flags;
+ /* SSL context, or NULL to create a new one. */
+ struct ssl_iostream_context *ssl_ctx;
+};
+
+/* Duplicate doveadm client settings. Note that the ssl_ctx is referenced by
+ this call, so it must be unreferenced later. */
+void doveadm_client_settings_dup(const struct doveadm_client_settings *src,
+ struct doveadm_client_settings *dest_r,
+ pool_t pool);
+
+int server_connection_create(const struct doveadm_client_settings *set,
struct server_connection **conn_r,
const char **error_r);
void server_connection_get_dest(struct server_connection *conn,
struct ip_addr *ip_r, in_port_t *port_r);
+const struct doveadm_client_settings *
+server_connection_get_settings(struct server_connection *conn);
void server_connection_set_print(struct server_connection *conn,
server_connection_print_t *callback,