static void ssl_handshake(struct ssl_proxy *proxy) { int ret, dir; ret = gnutls_handshake(proxy->session); if (ret >= 0) { /* handshake done, now we can start reading */ if (proxy->io_ssl != NULL) io_remove(proxy->io_ssl); proxy->io_plain = io_add(proxy->fd_plain, IO_READ, plain_input, proxy); proxy->io_ssl = io_add(proxy->fd_ssl, IO_READ, ssl_input, proxy); return; } if (handle_ssl_error(proxy, ret) < 0) return; /* i/o interrupted */ dir = gnutls_record_get_direction(proxy->session) == 0 ? IO_READ : IO_WRITE; if (proxy->io_ssl_dir != dir) { if (proxy->io_ssl != NULL) io_remove(proxy->io_ssl); proxy->io_ssl = io_add(proxy->fd_ssl, dir, ssl_handshake, proxy); proxy->io_ssl_dir = dir; } }
static void client_destroy(struct client *client) { char **app; i_set_failure_prefix("imap-urlauth[%s](%s): ", my_pid, client->access_user); if (client->url != NULL) { /* deinitialize url */ i_stream_close(client->input); o_stream_close(client->output); (void)client_run_url(client); i_assert(client->url == NULL); } imap_urlauth_worker_client_count--; DLLIST_REMOVE(&imap_urlauth_worker_clients, client); if (client->urlauth_ctx != NULL) imap_urlauth_deinit(&client->urlauth_ctx); if (client->mail_user != NULL) mail_user_unref(&client->mail_user); if (client->io != NULL) io_remove(&client->io); if (client->ctrl_io != NULL) io_remove(&client->ctrl_io); if (client->to_idle != NULL) timeout_remove(&client->to_idle); if (client->input != NULL) i_stream_destroy(&client->input); if (client->output != NULL) o_stream_destroy(&client->output); if (client->ctrl_input != NULL) i_stream_destroy(&client->ctrl_input); if (client->ctrl_output != NULL) o_stream_destroy(&client->ctrl_output); if (client->fd_in >= 0) net_disconnect(client->fd_in); if (client->fd_out >= 0 && client->fd_in != client->fd_out) net_disconnect(client->fd_out); if (client->fd_ctrl >= 0) net_disconnect(client->fd_ctrl); if (client->service_user != NULL) mail_storage_service_user_free(&client->service_user); i_free(client->access_user); array_foreach_modifiable(&client->access_apps, app) i_free(*app); array_free(&client->access_apps); i_free(client); imap_urlauth_worker_refresh_proctitle(); master_service_client_connection_destroyed(master_service); }
static void service_list_anvil_discard_input_stop(struct service_anvil_global *anvil) { if (anvil->io_blocking != NULL) { io_remove(&anvil->io_blocking); io_remove(&anvil->io_nonblocking); } }
static void iostream_pump_copy(struct iostream_pump *pump) { enum ostream_send_istream_result res; size_t old_size; o_stream_cork(pump->output); old_size = o_stream_get_max_buffer_size(pump->output); o_stream_set_max_buffer_size(pump->output, I_MIN(IO_BLOCK_SIZE, o_stream_get_max_buffer_size(pump->output))); res = o_stream_send_istream(pump->output, pump->input); o_stream_set_max_buffer_size(pump->output, old_size); o_stream_uncork(pump->output); switch(res) { case OSTREAM_SEND_ISTREAM_RESULT_ERROR_INPUT: io_remove(&pump->io); pump->callback(IOSTREAM_PUMP_STATUS_INPUT_ERROR, pump->context); return; case OSTREAM_SEND_ISTREAM_RESULT_ERROR_OUTPUT: io_remove(&pump->io); pump->callback(IOSTREAM_PUMP_STATUS_OUTPUT_ERROR, pump->context); return; case OSTREAM_SEND_ISTREAM_RESULT_WAIT_OUTPUT: i_assert(!pump->output->blocking); pump->waiting_output = TRUE; io_remove(&pump->io); return; case OSTREAM_SEND_ISTREAM_RESULT_FINISHED: pump->waiting_output = FALSE; io_remove(&pump->io); /* flush it */ switch (o_stream_flush(pump->output)) { case -1: pump->callback(IOSTREAM_PUMP_STATUS_OUTPUT_ERROR, pump->context); break; case 0: pump->waiting_output = TRUE; pump->completed = TRUE; break; default: pump->callback(IOSTREAM_PUMP_STATUS_INPUT_EOF, pump->context); break; } return; case OSTREAM_SEND_ISTREAM_RESULT_WAIT_INPUT: i_assert(!pump->input->blocking); pump->waiting_output = FALSE; return; } i_unreached(); }
static void ssl_input(struct ssl_proxy *proxy) { int rcvd, sent; rcvd = proxy_recv_ssl(proxy, proxy->outbuf_plain, sizeof(proxy->outbuf_plain)); if (rcvd <= 0) return; sent = net_transmit(proxy->fd_plain, proxy->outbuf_plain, (size_t)rcvd); if (sent == rcvd) return; if (sent < 0) { /* disconnected */ ssl_proxy_destroy(proxy); return; } /* everything wasn't sent - don't read anything until we've sent it all */ proxy->outbuf_pos_plain = 0; proxy->send_left_plain = rcvd - sent; io_remove(proxy->io_ssl); proxy->io_ssl = io_add(proxy->fd_ssl, IO_WRITE, ssl_output, proxy); }
void auth_client_connection_destroy(struct auth_client_connection **_conn) { struct auth_client_connection *conn = *_conn; *_conn = NULL; if (conn->fd == -1) return; DLLIST_REMOVE(&auth_client_connections, conn); i_stream_close(conn->input); o_stream_close(conn->output); if (conn->io != NULL) io_remove(&conn->io); net_disconnect(conn->fd); conn->fd = -1; if (conn->request_handler != NULL) { auth_request_handler_abort_requests(conn->request_handler); auth_request_handler_destroy(&conn->request_handler); } master_service_client_connection_destroyed(master_service); auth_client_connection_unref(&conn); }
static bool auth_worker_handle_list(struct auth_worker_client *client, unsigned int id, const char *const *args) { struct auth_worker_list_context *ctx; struct auth_userdb *userdb; unsigned int userdb_id; if (str_to_uint(args[0], &userdb_id) < 0) { i_error("BUG: Auth worker server sent us invalid LIST"); return FALSE; } userdb = auth_userdb_find_by_id(client->auth->userdbs, userdb_id); if (userdb == NULL) { i_error("BUG: LIST had invalid userdb ID"); return FALSE; } ctx = i_new(struct auth_worker_list_context, 1); ctx->client = client; ctx->id = id; ctx->userdb = userdb->userdb; io_remove(&ctx->client->io); o_stream_set_flush_callback(ctx->client->output, auth_worker_list_output, ctx); client->refcount++; ctx->iter = ctx->userdb->iface-> iterate_init(userdb->userdb, list_iter_callback, ctx); ctx->userdb->iface->iterate_next(ctx->iter); return TRUE; }
void master_login_auth_disconnect(struct master_login_auth *auth) { struct master_login_auth_request *request; while (auth->request_head != NULL) { request = auth->request_head; DLLIST2_REMOVE(&auth->request_head, &auth->request_tail, request); request_internal_failure(request, "Disconnected from auth server, aborting"); i_free(request); } hash_table_clear(auth->requests, FALSE); if (auth->to != NULL) timeout_remove(&auth->to); if (auth->io != NULL) io_remove(&auth->io); if (auth->fd != -1) { i_stream_destroy(&auth->input); o_stream_destroy(&auth->output); net_disconnect(auth->fd); auth->fd = -1; } auth->version_received = FALSE; }
void client_auth_respond(struct client *client, const char *response) { client->auth_waiting = FALSE; client_set_auth_waiting(client); auth_client_request_continue(client->auth_request, response); io_remove(&client->io); }
static void proxy_client_input(struct login_proxy *proxy) { const unsigned char *data; size_t size; ssize_t ret; proxy->last_io = ioloop_time; if (o_stream_get_buffer_used_size(proxy->server_output) > OUTBUF_THRESHOLD) { /* proxy's output buffer is already quite full. don't send more until we're below threshold. */ io_remove(&proxy->client_io); return; } if (i_stream_read_data(proxy->client_input, &data, &size, 0) < 0) { const char *errstr = i_stream_get_error(proxy->client_input); login_proxy_free_errstr(&proxy, errstr, FALSE); return; } o_stream_cork(proxy->server_output); ret = o_stream_send(proxy->server_output, data, size); o_stream_uncork(proxy->server_output); if (ret != (ssize_t)size) login_proxy_free_ostream(&proxy, proxy->server_output, TRUE); else i_stream_skip(proxy->client_input, ret); }
static void login_proxy_disconnect(struct login_proxy *proxy) { if (proxy->to != NULL) timeout_remove(&proxy->to); if (proxy->to_notify != NULL) timeout_remove(&proxy->to_notify); if (!proxy->num_waiting_connections_updated) { i_assert(proxy->state_rec->num_waiting_connections > 0); proxy->state_rec->num_waiting_connections--; } if (proxy->connected) { i_assert(proxy->state_rec->num_proxying_connections > 0); proxy->state_rec->num_proxying_connections--; } if (proxy->server_io != NULL) io_remove(&proxy->server_io); if (proxy->server_input != NULL) i_stream_destroy(&proxy->server_input); if (proxy->server_output != NULL) o_stream_destroy(&proxy->server_output); if (proxy->server_fd != -1) net_disconnect(proxy->server_fd); }
static void auth_client_send(struct auth_client_connection *conn, const char *cmd) { struct const_iovec iov[2]; iov[0].iov_base = cmd; iov[0].iov_len = strlen(cmd); iov[1].iov_base = "\n"; iov[1].iov_len = 1; o_stream_nsendv(conn->output, iov, 2); if (o_stream_get_buffer_used_size(conn->output) >= OUTBUF_THROTTLE_SIZE) { /* stop reading new requests until client has read the pending replies. */ if (conn->io != NULL) io_remove(&conn->io); } if (conn->auth->set->debug) { i_debug("client passdb out: %s", conn->auth->set->debug_passwords ? cmd : reply_line_hide_pass(cmd)); } }
void login_connection_deinit(struct login_connection **_conn) { struct login_connection *conn = *_conn; *_conn = NULL; if (conn->destroyed) return; conn->destroyed = TRUE; DLLIST_REMOVE(&login_connections, conn); io_remove(&conn->io); if (conn->input != NULL) i_stream_destroy(&conn->input); o_stream_destroy(&conn->output); if (close(conn->fd) < 0) i_error("close(login connection) failed: %m"); conn->fd = -1; if (conn->auth != NULL) auth_connection_deinit(&conn->auth); login_connection_unref(&conn); master_service_client_connection_destroyed(master_service); }
static void pop3c_client_disconnect(struct pop3c_client *client) { client->state = POP3C_CLIENT_STATE_DISCONNECTED; client->async_commands = 0; if (client->running) io_loop_stop(current_ioloop); if (client->dns_lookup != NULL) dns_lookup_abort(&client->dns_lookup); if (client->to != NULL) timeout_remove(&client->to); if (client->io != NULL) io_remove(&client->io); if (client->input != NULL) i_stream_destroy(&client->input); if (client->output != NULL) o_stream_destroy(&client->output); if (client->ssl_iostream != NULL) ssl_iostream_unref(&client->ssl_iostream); if (client->fd != -1) { if (close(client->fd) < 0) i_error("close(pop3c) failed: %m"); client->fd = -1; } client_login_callback(client, POP3C_COMMAND_STATE_DISCONNECTED, "Disconnected"); }
static void worker_connection_disconnect(struct worker_connection *conn) { unsigned int i, count = aqueue_count(conn->request_queue); if (conn->fd != -1) { io_remove(&conn->io); i_stream_destroy(&conn->input); o_stream_destroy(&conn->output); if (close(conn->fd) < 0) i_error("close(%s) failed: %m", conn->socket_path); conn->fd = -1; } /* cancel any pending requests */ if (count > 0) { i_error("Indexer worker disconnected, " "discarding %u requests for %s", count, conn->request_username); } /* conn->callback() can try to destroy us */ conn->refcount++; for (i = 0; i < count; i++) { void *const *contextp = array_idx(&conn->request_contexts, aqueue_idx(conn->request_queue, 0)); void *context = *contextp; aqueue_delete_tail(conn->request_queue); conn->callback(-1, context); } i_free_and_null(conn->request_username); worker_connection_unref(conn); }
static void login_proxy_free_final(struct login_proxy *proxy) { if (proxy->delayed_disconnect) { DLLIST_REMOVE(&login_proxies_disconnecting, proxy); i_assert(proxy->state_rec->num_delayed_client_disconnects > 0); if (--proxy->state_rec->num_delayed_client_disconnects == 0) proxy->state_rec->num_disconnects_since_ts = 0; timeout_remove(&proxy->to); } if (proxy->client_io != NULL) io_remove(&proxy->client_io); if (proxy->client_input != NULL) i_stream_destroy(&proxy->client_input); if (proxy->client_output != NULL) o_stream_destroy(&proxy->client_output); if (proxy->client_fd != -1) net_disconnect(proxy->client_fd); if (proxy->ssl_server_proxy != NULL) { ssl_proxy_destroy(proxy->ssl_server_proxy); ssl_proxy_free(&proxy->ssl_server_proxy); } i_free(proxy->host); i_free(proxy); }
static void cmd_append_finish(struct cmd_append_context *ctx) { if (ctx->save_parser != NULL) imap_parser_unref(&ctx->save_parser); i_assert(ctx->client->input_lock == ctx->cmd); if (ctx->client->io != NULL) io_remove(&ctx->client->io); /* we must put back the original flush callback before beginning to sync (the command is still unfinished at that point) */ o_stream_set_flush_callback(ctx->client->output, client_output, ctx->client); if (ctx->litinput != NULL) i_stream_unref(&ctx->litinput); if (ctx->input != NULL) i_stream_unref(&ctx->input); if (ctx->save_ctx != NULL) mailbox_save_cancel(&ctx->save_ctx); if (ctx->t != NULL) mailbox_transaction_rollback(&ctx->t); if (ctx->box != ctx->cmd->client->mailbox && ctx->box != NULL) mailbox_free(&ctx->box); }
bool cmd_idle(struct client_command_context *cmd) { struct client *client = cmd->client; struct cmd_idle_context *ctx; ctx = p_new(cmd->pool, struct cmd_idle_context, 1); ctx->cmd = cmd; ctx->client = client; idle_add_keepalive_timeout(ctx); idle_add_hibernate_timeout(ctx); if (client->mailbox != NULL) mailbox_notify_changes(client->mailbox, idle_callback, ctx); if (!client->state_import_idle_continue) client_send_line(client, "+ idling"); else { /* continuing an IDLE after hibernation */ client->state_import_idle_continue = FALSE; } io_remove(&client->io); client->io = io_add_istream(client->input, idle_client_input, ctx); cmd->func = cmd_idle_continue; cmd->context = ctx; /* check immediately if there are changes. if they came before we added mailbox-notifier, we wouldn't see them otherwise. */ if (client->mailbox != NULL) idle_sync_now(client->mailbox, ctx); return idle_client_handle_input(ctx, FALSE); }
void auth_server_connection_disconnect(struct auth_server_connection *conn, const char *reason) { conn->handshake_received = FALSE; conn->version_received = FALSE; conn->has_plain_mech = FALSE; conn->server_pid = 0; conn->connect_uid = 0; conn->cookie = NULL; array_clear(&conn->available_auth_mechs); if (conn->to != NULL) timeout_remove(&conn->to); if (conn->io != NULL) io_remove(&conn->io); if (conn->fd != -1) { i_stream_destroy(&conn->input); o_stream_destroy(&conn->output); if (close(conn->fd) < 0) i_error("close(auth server connection) failed: %m"); conn->fd = -1; } auth_server_connection_remove_requests(conn, reason); if (conn->client->connect_notify_callback != NULL) { conn->client->connect_notify_callback(conn->client, FALSE, conn->client->connect_notify_context); } }
bool client_handle_input(struct client *client) { bool ret, remove_io, handled_commands = FALSE; i_assert(!client->disconnected); client->handling_input = TRUE; do { T_BEGIN { ret = client_handle_next_command(client, &remove_io); } T_END; if (ret) handled_commands = TRUE; } while (ret && !client->disconnected && client->io != NULL); client->handling_input = FALSE; if (remove_io) io_remove(&client->io); else client_add_missing_io(client); if (!handled_commands) return FALSE; if (client->input_lock == NULL) cmd_sync_delayed(client); return TRUE; }
static void server_input(struct login_proxy *proxy) { unsigned char buf[OUTBUF_THRESHOLD]; ssize_t ret, ret2; proxy->last_io = ioloop_time; if (o_stream_get_buffer_used_size(proxy->client_output) > OUTBUF_THRESHOLD) { /* client's output buffer is already quite full. don't send more until we're below threshold. */ io_remove(&proxy->server_io); return; } ret = net_receive(proxy->server_fd, buf, sizeof(buf)); if (ret < 0) { login_proxy_free_errno(&proxy, errno, TRUE); return; } o_stream_cork(proxy->client_output); ret2 = o_stream_send(proxy->client_output, buf, ret); o_stream_uncork(proxy->client_output); if (ret2 != ret) login_proxy_free_ostream(&proxy, proxy->client_output, FALSE); }
static void client_input(struct client *client) { const char *const *args, *error; int ret; if (client->to_pending != NULL) timeout_remove(&client->to_pending); switch (i_stream_read(client->input)) { case -2: i_error("BUG: Stats client sent too much data"); client_destroy(&client); return; case -1: client_destroy(&client); return; } o_stream_cork(client->output); while ((args = client_read_next_line(client)) != NULL) { ret = client_handle_request(client, args, &error); if (ret < 0) { i_error("Stats client input error: %s", error); client_destroy(&client); return; } if (ret == 0) { o_stream_set_flush_pending(client->output, TRUE); io_remove(&client->io); break; } client->cmd_more = NULL; } o_stream_uncork(client->output); }
static void proxy_wait_connect(struct login_proxy *proxy) { errno = net_geterror(proxy->server_fd); if (errno != 0) { proxy_fail_connect(proxy); if (!proxy_try_reconnect(proxy)) { proxy_log_connect_error(proxy); login_proxy_free(&proxy); } return; } proxy->connected = TRUE; proxy->num_waiting_connections_updated = TRUE; proxy->state_rec->last_success = ioloop_timeval; i_assert(proxy->state_rec->num_waiting_connections > 0); proxy->state_rec->num_waiting_connections--; proxy->state_rec->num_proxying_connections++; proxy->state_rec->num_disconnects_since_ts = 0; if ((proxy->ssl_flags & PROXY_SSL_FLAG_YES) != 0 && (proxy->ssl_flags & PROXY_SSL_FLAG_STARTTLS) == 0) { if (login_proxy_starttls(proxy) < 0) { login_proxy_free(&proxy); return; } } else { io_remove(&proxy->server_io); proxy_plain_connected(proxy); } }
static void idle_finish(struct cmd_idle_context *ctx, bool done_ok, bool free_cmd) { struct client *client = ctx->client; if (ctx->keepalive_to != NULL) timeout_remove(&ctx->keepalive_to); if (ctx->sync_ctx != NULL) { /* we're here only in connection failure cases */ (void)imap_sync_deinit(ctx->sync_ctx, ctx->cmd); } o_stream_cork(client->output); if (client->io != NULL) io_remove(&client->io); if (client->mailbox != NULL) mailbox_notify_changes_stop(client->mailbox); if (done_ok) client_send_tagline(ctx->cmd, "OK Idle completed."); else client_send_tagline(ctx->cmd, "BAD Expected DONE."); o_stream_uncork(client->output); if (free_cmd) client_command_free(&ctx->cmd); }
int login_proxy_starttls(struct login_proxy *proxy) { int fd; if (proxy->server_input != NULL) i_stream_destroy(&proxy->server_input); if (proxy->server_output != NULL) o_stream_destroy(&proxy->server_output); io_remove(&proxy->server_io); fd = ssl_proxy_client_alloc(proxy->server_fd, &proxy->client->ip, proxy->client->pool, proxy->client->set, proxy->client->ssl_set, login_proxy_ssl_handshaked, proxy, &proxy->ssl_server_proxy); if (fd < 0) { client_log_err(proxy->client, t_strdup_printf( "proxy: SSL handshake failed to %s:%u", proxy->host, proxy->port)); return -1; } ssl_proxy_set_client(proxy->ssl_server_proxy, proxy->client); ssl_proxy_start(proxy->ssl_server_proxy); proxy->server_fd = fd; proxy_plain_connected(proxy); return 0; }
bool cmd_idle(struct client_command_context *cmd) { struct client *client = cmd->client; struct cmd_idle_context *ctx; ctx = p_new(cmd->pool, struct cmd_idle_context, 1); ctx->cmd = cmd; ctx->client = client; idle_add_keepalive_timeout(ctx); if (client->mailbox != NULL) mailbox_notify_changes(client->mailbox, idle_callback, ctx); client_send_line(client, "+ idling"); io_remove(&client->io); client->io = io_add(i_stream_get_fd(client->input), IO_READ, idle_client_input, ctx); cmd->func = cmd_idle_continue; cmd->context = ctx; /* check immediately if there are changes. if they came before we added mailbox-notifier, we wouldn't see them otherwise. */ if (client->mailbox != NULL) idle_sync_now(client->mailbox, ctx); return idle_client_handle_input(ctx, FALSE); }
void client_cmd_starttls(struct client *client) { if (client->tls) { client->v.notify_starttls(client, FALSE, "TLS is already active."); return; } if (!client_is_tls_enabled(client)) { client->v.notify_starttls(client, FALSE, "TLS support isn't enabled."); return; } /* remove input handler, SSL proxy gives us a new fd. we also have to remove it in case we have to wait for buffer to be flushed */ if (client->io != NULL) io_remove(&client->io); client->v.notify_starttls(client, TRUE, "Begin TLS negotiation now."); /* uncork the old fd */ o_stream_uncork(client->output); if (o_stream_flush(client->output) <= 0) { /* the buffer has to be flushed */ o_stream_set_flush_pending(client->output, TRUE); o_stream_set_flush_callback(client->output, client_output_starttls, client); } else { client_start_tls(client); } }
static void idle_client_input_more(struct cmd_idle_context *ctx) { struct client *client = ctx->client; client->last_input = ioloop_time; timeout_reset(client->to_idle); switch (i_stream_read(client->input)) { case -1: /* disconnected */ client_disconnect(client, "Disconnected in IDLE"); return; case -2: client->input_skip_line = TRUE; idle_finish(ctx, FALSE, TRUE); client_continue_pending_input(client); return; } if (ctx->sync_ctx != NULL) { /* we're still sending output to client. wait until it's all sent so we don't lose any changes. */ io_remove(&client->io); return; } if (idle_client_handle_input(ctx, TRUE)) { if (!client->disconnected) client_continue_pending_input(client); } }
int client_auth_begin(struct client *client, const char *mech_name, const char *init_resp) { if (!client->secured && strcmp(client->ssl_set->ssl, "required") == 0) { if (client->set->auth_verbose) { client_log(client, "Login failed: " "SSL required for authentication"); } client->auth_attempts++; client_auth_result(client, CLIENT_AUTH_RESULT_SSL_REQUIRED, NULL, "Authentication not allowed until SSL/TLS is enabled."); return 1; } client_ref(client); client->auth_initializing = TRUE; sasl_server_auth_begin(client, login_binary->protocol, mech_name, init_resp, sasl_callback); client->auth_initializing = FALSE; if (!client->authenticating) return 1; /* don't handle input until we get the initial auth reply */ if (client->io != NULL) io_remove(&client->io); client_set_auth_waiting(client); return 0; }
static bool cmd_putscript_start (struct client_command_context *cmd, const char *scriptname) { struct cmd_putscript_context *ctx; struct client *client = cmd->client; ctx = p_new(cmd->pool, struct cmd_putscript_context, 1); ctx->cmd = cmd; ctx->client = client; ctx->storage = client->storage; ctx->scriptname = scriptname; io_remove(&client->io); client->io = io_add(i_stream_get_fd(client->input), IO_READ, client_input_putscript, client); /* putscript is special because we're only waiting on client input, not client output, so disable the standard output handler until we're finished */ o_stream_unset_flush_callback(client->output); ctx->save_parser = managesieve_parser_create (client->input, client->set->managesieve_max_line_length); cmd->func = cmd_putscript_continue_parsing; cmd->context = ctx; return cmd_putscript_continue_parsing(cmd); }