struct client_connection_http {
struct client_connection conn;
+
struct http_server_connection *http_client;
struct http_server_request *http_server_request;
const struct http_request *http_request;
struct http_server_response *http_response;
+ struct io *io;
+ struct istream *input;
+ struct ostream *output;
+
struct json_parser *json_parser;
const struct doveadm_cmd_ver2 *cmd;
static void doveadm_http_server_send_response(void *context);
-void client_connection_destroy_http(struct client_connection *conn)
+static void
+client_connection_http_free(struct client_connection *_conn)
{
- struct client_connection_http *hconn =
- (struct client_connection_http *)conn;
+ struct client_connection_http *conn =
+ (struct client_connection_http *)_conn;
- if (hconn->http_client != NULL) {
+ io_remove(&conn->io);
+ o_stream_destroy(&conn->output);
+ i_stream_destroy(&conn->input);
+
+ if (conn->http_client != NULL) {
/* We're not in the lib-http/server's connection destroy callback. */
- http_server_connection_close(&hconn->http_client,
+ http_server_connection_close(&conn->http_client,
"Server shutting down");
}
}
pool = pool_alloconly_create("doveadm client", 1024*16);
conn = p_new(pool, struct client_connection_http, 1);
- conn->conn.pool = pool;
- conn->conn.http = TRUE;
if (client_connection_init(&conn->conn,
- CLIENT_CONNECTION_TYPE_HTTP, fd) < 0)
+ CLIENT_CONNECTION_TYPE_HTTP, pool, fd) < 0) {
+ pool_unref(&conn->conn.pool);
return NULL;
+ }
+ conn->conn.free = client_connection_http_free;
conn->http_client = http_server_connection_create(doveadm_http_server,
fd, fd, ssl, &doveadm_http_callbacks, conn);
- conn->conn.fd = -1;
return &conn->conn;
}
doveadm_http_server_connection_destroy(void *context,
const char *reason ATTR_UNUSED)
{
- struct client_connection_http *hconn =
+ struct client_connection_http *conn =
(struct client_connection_http *)context;
- struct client_connection *conn = &hconn->conn;
+ struct client_connection *bconn = &conn->conn;
- if (hconn->http_client == NULL) {
+ if (conn->http_client == NULL) {
/* already destroying client directly */
return;
}
/* HTTP connection is destroyed already now */
- hconn->http_client = NULL;
+ conn->http_client = NULL;
/* destroy the connection itself */
- client_connection_destroy(&conn);
+ client_connection_destroy(&bconn);
}
static void
(void)json_parser_deinit(&conn->json_parser, &error);
// we've already failed, ignore error
}
- if (conn->conn.output != NULL)
- o_stream_set_no_error_handling(conn->conn.output, TRUE);
+ if (conn->output != NULL)
+ o_stream_set_no_error_handling(conn->output, TRUE);
http_server_request_unref(&(conn->http_server_request));
http_server_switch_ioloop(doveadm_http_server);
static void doveadm_http_server_json_error(void *context, const char *error)
{
struct client_connection_http *conn = context;
- struct ostream *output = conn->conn.output;
+ struct ostream *output = conn->output;
string_t *escaped;
escaped = str_new(conn->conn.pool, 10);
static void doveadm_http_server_json_success(void *context, struct istream *result)
{
struct client_connection_http *conn = context;
- struct ostream *output = conn->conn.output;
+ struct ostream *output = conn->output;
string_t *escaped;
escaped = str_new(conn->conn.pool, 10);
prev_ioloop = current_ioloop;
i_zero(&cctx);
cctx.conn_type = conn->conn.type;
- cctx.input = conn->conn.input;
- cctx.output = conn->conn.output;
+ cctx.input = conn->input;
+ cctx.output = conn->output;
// create iostream
doveadm_print_ostream = iostream_temp_create("/tmp/doveadm.", 0);
client_connection_set_proctitle(&conn->conn, "");
io_loop_set_current(prev_ioloop);
- o_stream_switch_ioloop(conn->conn.output);
+ o_stream_switch_ioloop(conn->output);
io_loop_set_current(ioloop);
io_loop_destroy(&ioloop);
if (o_stream_nfinish(doveadm_print_ostream) < 0) {
i_info("Error writing output in command %s: %s",
conn->cmd->name,
- o_stream_get_error(conn->conn.output));
+ o_stream_get_error(conn->output));
doveadm_exit_code = EX_TEMPFAIL;
}
if (conn->first_row == TRUE)
conn->first_row = FALSE;
else
- o_stream_nsend_str(conn->conn.output,",");
+ o_stream_nsend_str(conn->output,",");
if (doveadm_exit_code != 0) {
if (doveadm_exit_code == 0 || doveadm_exit_code == EX_TEMPFAIL)
return FALSE;
conn->json_state = JSON_STATE_COMMAND;
conn->first_row = TRUE;
- o_stream_nsend_str(conn->conn.output,"[");
+ o_stream_nsend_str(conn->output,"[");
return TRUE;
case JSON_STATE_COMMAND:
if (type == JSON_TYPE_ARRAY_END) {
int ret;
if (conn->json_parser == NULL) {
- conn->json_parser = json_parser_init_flags(conn->conn.input, JSON_PARSER_NO_ROOT_OBJECT);
+ conn->json_parser = json_parser_init_flags(conn->input, JSON_PARSER_NO_ROOT_OBJECT);
}
while ((ret = doveadm_http_server_json_parse_next(conn, &type, &value)) == 1) {
break;
}
- if (!conn->conn.input->eof && ret == 0)
+ if (!conn->input->eof && ret == 0)
return;
- io_remove(&conn->conn.io);
+ io_remove(&conn->io);
doveadm_cmd_params_clean(&conn->pargv);
return;
}
- if (conn->conn.input->stream_errno != 0) {
+ if (conn->input->stream_errno != 0) {
http_server_request_fail_close(http_sreq, 400, "Client disconnected");
i_info("read(client) failed: %s",
- i_stream_get_error(conn->conn.input));
+ i_stream_get_error(conn->input));
return;
}
i_info("JSON parse error: %s", error);
return;
}
- o_stream_nsend_str(conn->conn.output,"]");
+ o_stream_nsend_str(conn->output,"]");
doveadm_http_server_send_response(conn);
}
static void
doveadm_http_server_send_api_v1(struct client_connection_http *conn)
{
- struct ostream *output = conn->conn.output;
+ struct ostream *output = conn->output;
const struct doveadm_cmd_ver2 *cmd;
const struct doveadm_cmd_param *par;
unsigned int i, k;
static void
doveadm_http_server_print_mounts(struct client_connection_http *conn)
{
- struct ostream *output = conn->conn.output;
+ struct ostream *output = conn->output;
unsigned int i;
o_stream_nsend_str(output, "[\n");
if (strcmp(http_req->method, "POST") == 0) {
/* handle request */
- conn->conn.input = http_req->payload;
- i_stream_set_name(conn->conn.input, net_ip2addr(&conn->conn.remote_ip));
- i_stream_ref(conn->conn.input);
- conn->conn.io = io_add_istream(conn->conn.input, *ep->handler, conn);
- conn->conn.output = iostream_temp_create_named
+ conn->input = http_req->payload;
+ i_stream_set_name(conn->input, net_ip2addr(&conn->conn.remote_ip));
+ i_stream_ref(conn->input);
+ conn->io = io_add_istream(conn->input, *ep->handler, conn);
+ conn->output = iostream_temp_create_named
("/tmp/doveadm.", 0, net_ip2addr(&conn->conn.remote_ip));
p_array_init(&conn->pargv, conn->conn.pool, 5);
ep->handler(conn);
} else {
- conn->conn.output = iostream_temp_create_named
+ conn->output = iostream_temp_create_named
("/tmp/doveadm.", 0, net_ip2addr(&conn->conn.remote_ip));
ep->handler(conn);
}
struct client_connection_http *conn = context;
struct http_server_response *http_resp = conn->http_response;
- if (conn->conn.output != NULL) {
- if (o_stream_nfinish(conn->conn.output) == -1) {
+ if (conn->output != NULL) {
+ if (o_stream_nfinish(conn->output) == -1) {
i_info("error writing output: %s",
- o_stream_get_error(conn->conn.output));
- o_stream_destroy(&conn->conn.output);
+ o_stream_get_error(conn->output));
+ o_stream_destroy(&conn->output);
http_server_response_update_status(http_resp, 500, "Internal server error");
} else {
// send the payload response
struct istream *is;
- is = iostream_temp_finish(&conn->conn.output, IO_BLOCK_SIZE);
+ is = iostream_temp_finish(&conn->output, IO_BLOCK_SIZE);
http_server_response_set_payload(http_resp, is);
i_stream_unref(&is);
}
const char *cmd_name);
int client_connection_init(struct client_connection *conn,
- enum client_connection_type type, int fd);
-void client_connection_deinit(struct client_connection *conn ATTR_UNUSED);
+ enum client_connection_type type, pool_t pool, int fd);
+void client_connection_destroy(struct client_connection **_conn);
void client_connection_set_proctitle(struct client_connection *conn,
const char *text);
-void client_connection_destroy_http(struct client_connection *conn);
-
void doveadm_http_server_init(void);
void doveadm_http_server_deinit(void);
+void doveadm_server_init(void);
+void doveadm_server_deinit(void);
+
#endif
#include "master-service-ssl.h"
#include "mail-storage-service.h"
#include "doveadm-util.h"
-#include "doveadm-server.h"
#include "doveadm-mail.h"
#include "doveadm-print.h"
+#include "doveadm-server.h"
#include "client-connection-private.h"
#include <unistd.h>
#define MAX_INBUF_SIZE (1024*1024)
-static void client_connection_input(struct client_connection *conn);
+struct client_connection_tcp {
+ struct client_connection conn;
+
+ int fd;
+ struct io *io;
+ struct istream *input;
+ struct ostream *output;
+ struct ostream *log_out;
+ struct ssl_iostream *ssl_iostream;
+
+ bool handshaked:1;
+ bool authenticated:1;
+ bool io_setup:1;
+ bool use_multiplex:1;
+};
+
+static void
+client_connection_tcp_input(struct client_connection_tcp *conn);
+static void
+client_connection_tcp_destroy(struct client_connection_tcp **_conn);
static failure_callback_t *orig_error_callback, *orig_fatal_callback;
static failure_callback_t *orig_info_callback, *orig_debug_callback = NULL;
doveadm_server_log_handler(const struct failure_context *ctx,
const char *format, va_list args)
{
- if (!log_recursing && doveadm_client != NULL &&
- doveadm_client->log_out != NULL) T_BEGIN {
- struct ostream *log_out = doveadm_client->log_out;
+ struct client_connection_tcp *conn = NULL;
+
+ if (doveadm_client != NULL &&
+ doveadm_client->type == CLIENT_CONNECTION_TYPE_TCP)
+ conn = (struct client_connection_tcp *)doveadm_client;
+
+ if (!log_recursing && conn != NULL &&
+ conn->log_out != NULL) T_BEGIN {
+ struct ostream *log_out = conn->log_out;
char c;
const char *ptr, *start;
bool corked;
}
static void
-doveadm_cmd_server_post(struct client_connection *conn, const char *cmd_name)
+doveadm_cmd_server_post(struct client_connection_tcp *conn, const char *cmd_name)
{
const char *str = NULL;
}
static void
-doveadm_cmd_server_run_ver2(struct client_connection *conn,
+doveadm_cmd_server_run_ver2(struct client_connection_tcp *conn,
int argc, const char *const argv[],
struct doveadm_cmd_context *cctx)
{
}
static void
-doveadm_cmd_server_run(struct client_connection *conn,
+doveadm_cmd_server_run(struct client_connection_tcp *conn,
int argc, const char *const argv[],
const struct doveadm_cmd *cmd)
{
}
static void
-doveadm_mail_cmd_server_run(struct client_connection *conn,
+doveadm_mail_cmd_server_run(struct client_connection_tcp *conn,
struct doveadm_mail_cmd_context *mctx)
{
const char *error;
pool_unref(&mctx->pool);
}
-static int doveadm_cmd_handle(struct client_connection *conn,
+static int doveadm_cmd_handle(struct client_connection_tcp *conn,
const char *cmd_name,
int argc, const char *const argv[],
struct doveadm_cmd_context *cctx)
return -1;
}
} else {
- if (doveadm_mail_cmd_server_parse(mail_cmd, conn->set,
+ if (doveadm_mail_cmd_server_parse(mail_cmd, conn->conn.set,
argc, argv,
cctx, &mctx) < 0)
return -1;
return doveadm_exit_code == 0 ? 0 : -1;
}
-static bool client_handle_command(struct client_connection *conn,
+static bool client_handle_command(struct client_connection_tcp *conn,
const char *const *args)
{
struct doveadm_cmd_context cctx;
return FALSE;
}
i_zero(&cctx);
- cctx.conn_type = conn->type;
+ cctx.conn_type = conn->conn.type;
cctx.input = conn->input;
cctx.output = conn->output;
- cctx.local_ip = conn->local_ip;
- cctx.remote_ip = conn->remote_ip;
- cctx.local_port = conn->local_port;
- cctx.remote_port = conn->remote_port;
+ cctx.local_ip = conn->conn.local_ip;
+ cctx.remote_ip = conn->conn.remote_ip;
+ cctx.local_port = conn->conn.local_port;
+ cctx.remote_port = conn->conn.remote_port;
doveadm_exit_code = 0;
flags = args[0];
}
}
- if (!doveadm_client_is_allowed_command(conn->set, cmd_name)) {
+ if (!doveadm_client_is_allowed_command(conn->conn.set, cmd_name)) {
i_error("doveadm client isn't allowed to use command: %s",
cmd_name);
return FALSE;
}
- client_connection_set_proctitle(conn, cmd_name);
+ client_connection_set_proctitle(&conn->conn, cmd_name);
o_stream_cork(conn->output);
if (doveadm_cmd_handle(conn, cmd_name, argc-2, args+2, &cctx) < 0)
o_stream_nsend(conn->output, "\n-\n", 3);
o_stream_uncork(conn->output);
- client_connection_set_proctitle(conn, "");
+ client_connection_set_proctitle(&conn->conn, "");
/* flush the output and possibly run next command */
net_set_nonblock(conn->fd, FALSE);
}
static int
-client_connection_authenticate(struct client_connection *conn)
+client_connection_tcp_authenticate(struct client_connection_tcp *conn)
{
+ const struct doveadm_settings *set = conn->conn.set;
const char *line, *pass;
buffer_t *plain;
const unsigned char *data;
return 0;
}
- if (*conn->set->doveadm_password == '\0') {
+ if (*set->doveadm_password == '\0') {
i_error("doveadm_password not set, "
"remote authentication disabled");
return -1;
return -1;
}
pass = t_strndup(data + 9, size - 9);
- if (strlen(pass) != strlen(conn->set->doveadm_password) ||
- !mem_equals_timing_safe(pass, conn->set->doveadm_password,
+ if (strlen(pass) != strlen(set->doveadm_password) ||
+ !mem_equals_timing_safe(pass, set->doveadm_password,
strlen(pass))) {
i_error("doveadm client authenticated with wrong password");
return -1;
return 1;
}
-static void client_log_disconnect_error(struct client_connection *conn)
+static void client_log_disconnect_error(struct client_connection_tcp *conn)
{
const char *error;
i_error("doveadm client disconnected before handshake: %s", error);
}
-static void client_connection_input(struct client_connection *conn)
+static void
+client_connection_tcp_input(struct client_connection_tcp *conn)
{
const char *line;
bool ok = TRUE;
if ((line = i_stream_read_next_line(conn->input)) == NULL) {
if (conn->input->eof || conn->input->stream_errno != 0) {
client_log_disconnect_error(conn);
- client_connection_destroy(&conn);
+ client_connection_tcp_destroy(&conn);
}
return;
}
DOVEADM_SERVER_PROTOCOL_VERSION_MAJOR, &minor)) {
i_error("doveadm client not compatible with this server "
"(mixed old and new binaries?)");
- client_connection_destroy(&conn);
+ client_connection_tcp_destroy(&conn);
return;
}
if (minor > 0) {
conn->handshaked = TRUE;
}
if (!conn->authenticated) {
- if ((ret = client_connection_authenticate(conn)) <= 0) {
+ if ((ret = client_connection_tcp_authenticate(conn)) <= 0) {
if (ret < 0) {
o_stream_nsend(conn->output, "-\n", 2);
- client_connection_destroy(&conn);
+ client_connection_tcp_destroy(&conn);
}
return;
}
} T_END;
}
if (conn->input->eof || conn->input->stream_errno != 0 || !ok)
- client_connection_destroy(&conn);
+ client_connection_tcp_destroy(&conn);
}
-static int client_connection_init_ssl(struct client_connection *conn)
+static int
+client_connection_tcp_init_ssl(struct client_connection_tcp *conn)
{
const char *error;
}
static void
-client_connection_send_auth_handshake(struct client_connection *
+client_connection_tcp_send_auth_handshake(struct client_connection_tcp *
conn, int listen_fd)
{
const char *listen_path;
}
}
-void client_connection_destroy(struct client_connection **_conn)
+static void
+client_connection_tcp_free(struct client_connection *_conn)
{
- struct client_connection *conn = *_conn;
+ struct client_connection_tcp *conn =
+ (struct client_connection_tcp *)_conn;
- *_conn = NULL;
+ i_assert(_conn->type == CLIENT_CONNECTION_TYPE_TCP);
doveadm_print_deinit();
-
- if (conn->http)
- client_connection_destroy_http(conn);
+ doveadm_print_ostream = NULL;
if (conn->ssl_iostream != NULL)
ssl_iostream_destroy(&conn->ssl_iostream);
- o_stream_destroy(&conn->output);
-
- io_remove(&conn->io);
-
if (conn->log_out != NULL) {
doveadm_server_restore_logs();
o_stream_unref(&conn->log_out);
}
+ io_remove(&conn->io);
+ o_stream_destroy(&conn->output);
i_stream_destroy(&conn->input);
-
i_close_fd(&conn->fd);
- pool_unref(&conn->pool);
-
- doveadm_print_ostream = NULL;
-
- client_connection_deinit(conn);
}
struct client_connection *
client_connection_tcp_create(int fd, int listen_fd, bool ssl)
{
- struct client_connection *conn;
+ struct client_connection_tcp *conn;
pool_t pool;
pool = pool_alloconly_create("doveadm client", 1024*16);
- conn = p_new(pool, struct client_connection, 1);
- conn->pool = pool;
+ conn = p_new(pool, struct client_connection_tcp, 1);
+ conn->fd = fd;
- if (client_connection_init(conn,
- CLIENT_CONNECTION_TYPE_TCP, fd) < 0)
+ if (client_connection_init(&conn->conn,
+ CLIENT_CONNECTION_TYPE_TCP, pool, fd) < 0) {
+ client_connection_tcp_destroy(&conn);
return NULL;
- doveadm_print_init(DOVEADM_PRINT_TYPE_SERVER);
+ }
+ conn->conn.free = client_connection_tcp_free;
- conn->name = conn->remote_ip.family == 0 ? "<local>" :
- p_strdup(pool, net_ip2addr(&conn->remote_ip));
- conn->io = io_add(fd, IO_READ, client_connection_input, conn);
+ doveadm_print_init(DOVEADM_PRINT_TYPE_SERVER);
+
+ conn->io = io_add(fd, IO_READ, client_connection_tcp_input, conn);
conn->input = i_stream_create_fd(fd, MAX_INBUF_SIZE);
conn->output = o_stream_create_fd(fd, (size_t)-1);
- i_stream_set_name(conn->input, conn->name);
- o_stream_set_name(conn->output, conn->name);
+ i_stream_set_name(conn->input, conn->conn.name);
+ o_stream_set_name(conn->output, conn->conn.name);
o_stream_set_no_error_handling(conn->output, TRUE);
if (ssl) {
- if (client_connection_init_ssl(conn) < 0) {
- client_connection_destroy(&conn);
+ if (client_connection_tcp_init_ssl(conn) < 0) {
+ client_connection_tcp_destroy(&conn);
return NULL;
}
}
- client_connection_send_auth_handshake(conn, listen_fd);
- client_connection_set_proctitle(conn, "");
+ client_connection_tcp_send_auth_handshake(conn, listen_fd);
+ client_connection_set_proctitle(&conn->conn, "");
+
+ return &conn->conn;
+}
- return conn;
+static void
+client_connection_tcp_destroy(struct client_connection_tcp **_conn)
+{
+ struct client_connection_tcp *conn = *_conn;
+ struct client_connection *bconn = &conn->conn;
+
+ *_conn = NULL;
+ client_connection_destroy(&bconn);
}
}
int client_connection_init(struct client_connection *conn,
- enum client_connection_type type, int fd)
+ enum client_connection_type type, pool_t pool, int fd)
{
const char *ip;
i_assert(type != CLIENT_CONNECTION_TYPE_CLI);
- conn->fd = fd;
conn->type = type;
+ conn->pool = pool;
(void)net_getsockname(fd, &conn->local_ip, &conn->local_port);
(void)net_getpeername(fd, &conn->remote_ip, &conn->remote_port);
if (ip[0] != '\0')
i_set_failure_prefix("doveadm(%s): ", ip);
- if (client_connection_read_settings(conn) < 0) {
- client_connection_destroy(&conn);
- return -1;
- }
- return 0;
+ conn->name = conn->remote_ip.family == 0 ? "<local>" :
+ p_strdup(pool, net_ip2addr(&conn->remote_ip));
+
+ return client_connection_read_settings(conn);
}
-void client_connection_deinit(struct client_connection *conn ATTR_UNUSED)
+void client_connection_destroy(struct client_connection **_conn)
{
+ struct client_connection *conn = *_conn;
+
+ *_conn = NULL;
+
+ if (conn->free != NULL)
+ conn->free(conn);
+
doveadm_client = NULL;
master_service_client_connection_destroyed(master_service);
if (doveadm_verbose_proctitle)
process_title_set("[idling]");
+
+ pool_unref(&conn->pool);
}
void client_connection_set_proctitle(struct client_connection *conn,
process_title_set(str);
}
+void doveadm_server_init(void)
+{
+ doveadm_http_server_init();
+}
+void doveadm_server_deinit(void)
+{
+ if (doveadm_client != NULL)
+ client_connection_destroy(&doveadm_client);
+ doveadm_http_server_deinit();
+}
struct client_connection {
pool_t pool;
enum client_connection_type type;
-
- int fd;
const char *name;
- struct io *io;
- struct istream *input;
- struct ostream *output;
- struct ostream *log_out;
- struct ssl_iostream *ssl_iostream;
+
struct ip_addr local_ip, remote_ip;
in_port_t local_port, remote_port;
+
const struct doveadm_settings *set;
- bool handshaked:1;
- bool authenticated:1;
- bool http:1;
- bool io_setup:1;
- bool use_multiplex:1;
+ void (*free)(struct client_connection *conn);
};
struct client_connection *
client_connection_tcp_create(int fd, int listen_fd, bool ssl);
struct client_connection *
client_connection_http_create(int fd, bool ssl);
-void client_connection_destroy(struct client_connection **conn);
#endif
if (doveadm_verbose_proctitle)
process_title_set("[idling]");
- doveadm_http_server_init();
doveadm_cmds_init();
doveadm_register_auth_server_commands();
doveadm_dump_init();
doveadm_mail_init();
+ doveadm_server_init();
dict_drivers_register_builtin();
doveadm_load_modules();
}
static void main_deinit(void)
{
- if (doveadm_client != NULL)
- client_connection_destroy(&doveadm_client);
+ doveadm_server_deinit();
doveadm_mail_deinit();
doveadm_dump_deinit();
doveadm_unload_modules();
dict_drivers_unregister_builtin();
doveadm_print_deinit();
doveadm_cmds_deinit();
- doveadm_http_server_deinit();
pool_unref(&doveadm_settings_pool);
}