server-connection.c revision b3c095d1fb0bb86695d92c2045eb09e985623934
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina/* Copyright (c) 2010-2017 Dovecot authors, see the included COPYING file */
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březinastatic struct server_connection *printing_conn = NULL;
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březinastatic ARRAY(struct doveadm_server *) print_pending_servers = ARRAY_INIT;
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březinastatic void server_connection_input(struct server_connection *conn);
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březinastatic bool server_connection_input_one(struct server_connection *conn);
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březinastatic void server_set_print_pending(struct doveadm_server *server)
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina if (!array_is_created(&print_pending_servers))
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina array_foreach(&print_pending_servers, serverp) {
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina array_append(&print_pending_servers, &server, 1);
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březinastatic void server_print_connection_released(struct doveadm_server *server)
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina unsigned int i, count;
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina conns = array_get(&server->connections, &count);
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina for (i = 0; i < count; i++) {
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina if (!array_is_created(&print_pending_servers))
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina array_foreach(&print_pending_servers, serverp)
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březinastatic int server_connection_send_cmd_input_more(struct server_connection *conn)
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina /* ostream-dot writes only up to max buffer size, so keep it non-zero */
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina o_stream_set_max_buffer_size(conn->cmd_output, IO_BLOCK_SIZE);
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina res = o_stream_send_istream(conn->cmd_output, conn->cmd_input);
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina o_stream_set_max_buffer_size(conn->cmd_output, (size_t)-1);
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina case OSTREAM_SEND_ISTREAM_RESULT_ERROR_OUTPUT:
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina if (res == OSTREAM_SEND_ISTREAM_RESULT_FINISHED) {
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina if ((ret = o_stream_flush(conn->cmd_output)) == 0)
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina else if (ret < 0) {
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březinastatic void server_connection_send_cmd_input(struct server_connection *conn)
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina conn->cmd_output = o_stream_create_dot(conn->output, TRUE);
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina (void)server_connection_send_cmd_input_more(conn);
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březinastatic int server_connection_output(struct server_connection *conn)
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina if (ret > 0 && conn->cmd_input != NULL && conn->delayed_cmd == NULL)
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina ret = server_connection_send_cmd_input_more(conn);
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březinaserver_connection_callback(struct server_connection *conn,
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina server_cmd_callback_t *callback = conn->callback;
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březinastatic void stream_data(string_t *str, const unsigned char *data, size_t size)
84060f52e782b079337ee7a99bb7ad17e8c84fbbPavel Březinastatic void server_flush_field(struct server_connection *conn, string_t *str,
84060f52e782b079337ee7a99bb7ad17e8c84fbbPavel Březinaserver_handle_input(struct server_connection *conn,
84060f52e782b079337ee7a99bb7ad17e8c84fbbPavel Březina /* continue printing */
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina /* someone else is printing. don't continue until it
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina /* last character is an escape */
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina i_error("doveadm server sent broken print input");
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina server_flush_field(conn, str, data + start, i - start);
b0c4eb194cf1414d3440e0cccfb9af9074388c08Pavel Březinastatic void server_connection_authenticated(struct server_connection *conn)
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina o_stream_nsend_str(conn->output, conn->delayed_cmd);
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březinaserver_connection_authenticate(struct server_connection *conn)
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina "can't authenticate to remote server");
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina str_append(plain, conn->set->doveadm_username);
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina str_append(plain, conn->set->doveadm_password);
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina o_stream_nsend(conn->output, cmd->data, cmd->used);
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březinastatic void server_log_disconnect_error(struct server_connection *conn)
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina ssl_iostream_get_last_error(conn->ssl_iostream);
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina error = conn->input->stream_errno == 0 ? "EOF" :
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina i_error("doveadm server disconnected before handshake: %s", error);
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březinastatic void server_connection_input(struct server_connection *conn)
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina if ((line = i_stream_read_next_line(conn->input)) == NULL) {
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina if (conn->input->eof || conn->input->stream_errno != 0) {
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina if (server_connection_authenticate(conn) < 0) {
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina i_error("doveadm server sent invalid handshake: %s",
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina /* disconnected */
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina if ((line = i_stream_next_line(conn->input)) == NULL)
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina i_error("doveadm authentication failed (%s)", line+1);
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březinastatic bool server_connection_input_one(struct server_connection *conn)
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina const unsigned char *data;
64497d479e92ebc34717c20c3d017f1823f9e630Jakub Hrozek const char *line;
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina i_error("doveadm server sent unexpected input");
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina /* fall through */
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina /* old doveadm-server */
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina server_connection_callback(conn, exit_code, line);
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina /* we're finished, close the connection */
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březinastatic int server_connection_read_settings(struct server_connection *conn)
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina const struct setting_parser_info *set_roots[] = {
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina (void)net_getsockname(conn->fd, &input.local_ip, &port);
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina (void)net_getpeername(conn->fd, &input.remote_ip, &port);
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina if (master_service_settings_read(master_service, &input,
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina i_error("Error reading configuration: %s", error);
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina set = master_service_settings_get_others(master_service)[0];
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina conn->set = settings_dup(&doveadm_setting_parser_info, set, conn->pool);
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březinastatic int server_connection_ssl_handshaked(const char **error_r, void *context)
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina const char *host, *p;
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina if (ssl_iostream_check_cert_validity(conn->ssl_iostream, host, error_r) < 0)
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina i_debug("%s: SSL handshake successful", conn->server->name);
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březinastatic int server_connection_init_ssl(struct server_connection *conn)
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina if (io_stream_create_ssl_client(conn->server->ssl_ctx,
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina i_error("Couldn't initialize SSL client: %s", error);
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina ssl_iostream_set_handshake_callback(conn->ssl_iostream,
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina if (ssl_iostream_handshake(conn->ssl_iostream) < 0) {
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina ssl_iostream_get_last_error(conn->ssl_iostream));
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březinaint server_connection_create(struct doveadm_server *server,
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina#define DOVEADM_SERVER_HANDSHAKE "VERSION\tdoveadm-server\t1\t0\n"
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina pool = pool_alloconly_create("doveadm server connection", 1024*16);
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina conn = p_new(pool, struct server_connection, 1);
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina conn->fd = doveadm_connect_with_default_port(server->name,
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina conn->io = io_add(conn->fd, IO_READ, server_connection_input, conn);
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina conn->input = i_stream_create_fd(conn->fd, MAX_INBUF_SIZE);
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina conn->output = o_stream_create_fd(conn->fd, (size_t)-1);
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina o_stream_set_flush_callback(conn->output, server_connection_output, conn);
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina o_stream_set_name(conn->output, server->name);
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina array_append(&conn->server->connections, &conn, 1);
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina if (server_connection_read_settings(conn) < 0 ||
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina o_stream_set_no_error_handling(conn->output, TRUE);
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina o_stream_nsend_str(conn->output, DOVEADM_SERVER_HANDSHAKE);
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březinavoid server_connection_destroy(struct server_connection **_conn)
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina unsigned int i, count;
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina conns = array_get(&conn->server->connections, &count);
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina for (i = 0; i < count; i++) {
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina array_delete(&conn->server->connections, i, 1);
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina ssl_iostream_get_last_error(conn->ssl_iostream);
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina error = conn->input->stream_errno == 0 ? "EOF" :
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina server_connection_callback(conn, SERVER_EXIT_CODE_DISCONNECTED,
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březina /* close cmd_output after its parent, so the "." isn't sent */
a641a13889d617aca6bd998025e9087e822ff7f0Pavel Březinaserver_connection_get_server(struct server_connection *conn)
bc854800cc67271205d63136daaf68d7863cea6bJustin Stephensonvoid server_connection_cmd(struct server_connection *conn, const char *line,
bc854800cc67271205d63136daaf68d7863cea6bJustin Stephenson server_cmd_callback_t *callback, void *context)
84060f52e782b079337ee7a99bb7ad17e8c84fbbPavel Březina conn->delayed_cmd = p_strdup(conn->pool, line);
84060f52e782b079337ee7a99bb7ad17e8c84fbbPavel Březinabool server_connection_is_idle(struct server_connection *conn)