int auth_server_connection_connect(struct auth_server_connection *conn) { const char *handshake; int fd; i_assert(conn->fd == -1); conn->last_connect = ioloop_time; if (conn->to != NULL) timeout_remove(&conn->to); /* max. 1 second wait here. */ fd = net_connect_unix_with_retries(conn->client->auth_socket_path, 1000); if (fd == -1) { if (errno == EACCES) { i_error("auth: %s", eacces_error_get("connect", conn->client->auth_socket_path)); } else { i_error("auth: connect(%s) failed: %m", conn->client->auth_socket_path); } return -1; } conn->fd = fd; conn->io = io_add(fd, IO_READ, auth_server_connection_input, conn); conn->input = i_stream_create_fd(fd, AUTH_SERVER_CONN_MAX_LINE_LENGTH, FALSE); conn->output = o_stream_create_fd(fd, (size_t)-1, FALSE); handshake = t_strdup_printf("VERSION\t%u\t%u\nCPID\t%u\n", AUTH_CLIENT_PROTOCOL_MAJOR_VERSION, AUTH_CLIENT_PROTOCOL_MINOR_VERSION, conn->client->client_pid); if (o_stream_send_str(conn->output, handshake) < 0) { i_warning("Error sending handshake to auth server: %m"); auth_server_connection_disconnect(conn); return -1; } conn->to = timeout_add(AUTH_HANDSHAKE_TIMEOUT, auth_client_handshake_timeout, conn); return 0; }
static int lmtp_client_connect(struct lmtp_client *client) { client->fd = net_connect_ip(&client->ip, client->port, NULL); if (client->fd == -1) { i_error("lmtp client: connect(%s, %u) failed: %m", client->host, client->port); return -1; } client->input = i_stream_create_fd(client->fd, LMTP_MAX_LINE_LEN, FALSE); client->output = o_stream_create_fd(client->fd, (size_t)-1, FALSE); o_stream_set_no_error_handling(client->output, TRUE); o_stream_set_flush_callback(client->output, lmtp_client_output, client); /* we're already sending data in ostream, so can't use IO_WRITE here */ client->io = io_add(client->fd, IO_READ, lmtp_client_wait_connect, client); return 0; }
static void lmtp_client_wait_connect(struct lmtp_client *client) { int err; err = net_geterror(client->fd); if (err != 0) { i_error("lmtp client: connect(%s, %u) failed: %s", client->host, client->port, strerror(err)); lmtp_client_fail(client, ERRSTR_TEMP_REMOTE_FAILURE " (connect)"); return; } if (client->to != NULL) timeout_remove(&client->to); io_remove(&client->io); client->io = io_add(client->fd, IO_READ, lmtp_client_input, client); lmtp_client_input(client); }
static int proxy_client_output(struct login_proxy *proxy) { proxy->last_io = ioloop_time; if (o_stream_flush(proxy->client_output) < 0) { login_proxy_free_ostream(&proxy, proxy->client_output, FALSE); return 1; } if (proxy->server_io == NULL && o_stream_get_buffer_used_size(proxy->client_output) < OUTBUF_THRESHOLD) { /* there's again space in client's output buffer, so we can read more from proxy. */ proxy->server_io = io_add(proxy->server_fd, IO_READ, server_input, proxy); } return 1; }
static void replicator_connection_connect(struct replicator_connection *conn) { unsigned int n; int fd = -1; if (conn->fd != -1) return; if (conn->port == 0) { fd = net_connect_unix(conn->path); if (fd == -1) i_error("net_connect_unix(%s) failed: %m", conn->path); } else { for (n = 0; n < conn->ips_count; n++) { unsigned int idx = conn->ip_idx; conn->ip_idx = (conn->ip_idx + 1) % conn->ips_count; fd = net_connect_ip(&conn->ips[idx], conn->port, NULL); if (fd != -1) break; i_error("connect(%s, %u) failed: %m", net_ip2addr(&conn->ips[idx]), conn->port); } } if (fd == -1) { if (conn->to == NULL) { conn->to = timeout_add(REPLICATOR_RECONNECT_MSECS, replicator_connection_connect, conn); } return; } if (conn->to != NULL) timeout_remove(&conn->to); conn->fd = fd; conn->io = io_add(fd, IO_READ, replicator_input, conn); conn->input = i_stream_create_fd(fd, MAX_INBUF_SIZE, FALSE); conn->output = o_stream_create_fd(fd, (size_t)-1, FALSE); o_stream_set_no_error_handling(conn->output, TRUE); o_stream_nsend_str(conn->output, REPLICATOR_HANDSHAKE); o_stream_set_flush_callback(conn->output, replicator_output, conn); }
void auth_client_connection_create(struct auth *auth, int fd, bool login_requests, bool token_auth) { static unsigned int connect_uid_counter = 0; struct auth_client_connection *conn; const char *mechanisms; string_t *str; conn = i_new(struct auth_client_connection, 1); conn->auth = auth; conn->refcount = 1; conn->connect_uid = ++connect_uid_counter; conn->login_requests = login_requests; conn->token_auth = token_auth; random_fill(conn->cookie, sizeof(conn->cookie)); conn->fd = fd; conn->input = i_stream_create_fd(fd, AUTH_CLIENT_MAX_LINE_LENGTH); conn->output = o_stream_create_fd(fd, (size_t)-1); o_stream_set_no_error_handling(conn->output, TRUE); o_stream_set_flush_callback(conn->output, auth_client_output, conn); conn->io = io_add(fd, IO_READ, auth_client_input, conn); DLLIST_PREPEND(&auth_client_connections, conn); if (token_auth) { mechanisms = t_strconcat("MECH\t", mech_dovecot_token.mech_name, "\n", NULL); } else { mechanisms = str_c(auth->reg->handshake); } str = t_str_new(128); str_printfa(str, "VERSION\t%u\t%u\n%sSPID\t%s\nCUID\t%u\nCOOKIE\t", AUTH_CLIENT_PROTOCOL_MAJOR_VERSION, AUTH_CLIENT_PROTOCOL_MINOR_VERSION, mechanisms, my_pid, conn->connect_uid); binary_to_hex_append(str, conn->cookie, sizeof(conn->cookie)); str_append(str, "\nDONE\n"); if (o_stream_send(conn->output, str_data(str), str_len(str)) < 0) auth_client_disconnected(&conn); }
static void list_iter_deinit(struct auth_worker_list_context *ctx) { struct auth_worker_client *client = ctx->client; string_t *str; i_assert(client->io == NULL); str = t_str_new(32); if (ctx->userdb->iface->iterate_deinit(ctx->iter) < 0) str_printfa(str, "%u\tFAIL\n", ctx->id); else str_printfa(str, "%u\tOK\n", ctx->id); auth_worker_send_reply(client, str); client->io = io_add(client->fd, IO_READ, auth_worker_input, client); o_stream_set_flush_callback(client->output, auth_worker_output, client); auth_worker_client_unref(&client); i_free(ctx); }
struct auth_worker_client * auth_worker_client_create(struct auth *auth, int fd) { struct auth_worker_client *client; client = i_new(struct auth_worker_client, 1); client->refcount = 1; client->auth = auth; client->fd = fd; client->input = i_stream_create_fd(fd, AUTH_WORKER_MAX_LINE_LENGTH, FALSE); client->output = o_stream_create_fd(fd, (size_t)-1, FALSE); o_stream_set_flush_callback(client->output, auth_worker_output, client); client->io = io_add(fd, IO_READ, auth_worker_input, client); auth_worker_client = client; return client; }
int io_socket_accept(io_atom *io, io_proc proc, int flags, io_atom *listener, socket_addr *remote) { struct sockaddr_in pin; socklen_t plen; int err; plen = sizeof(pin); while((io->fd = accept(listener->fd, (struct sockaddr*)&pin, &plen)) < 0) { if(errno == EINTR) { // This call was interrupted by a signal. Try again and // see if we receive a connection. continue; } if(errno == EAGAIN || errno == EWOULDBLOCK) { // No pending connections are present (socket is nonblocking). return -1; } // Probably there is a network error pending for this // connection (already!). Should probably just ignore it...? return -1; } // Excellent. We managed to connect to the remote socket. if(set_nonblock(io->fd) < 0) { close(io->fd); return -1; } io->proc = proc; err = io_add(io, flags); if(err < 0) { close(io->fd); return -1; } if(remote) { remote->addr = pin.sin_addr; remote->port = (int)ntohs(pin.sin_port); } return io->fd; }
static void proxy_client_worker_msg_get_done(struct proxy_client_dsync_worker *worker) { struct istream *input = worker->msg_get_data.input; i_assert(worker->io == NULL); if (input->eof) proxy_client_worker_msg_get_finish(worker); else { /* saving read the message only partially. we'll need to read the input until EOF or we'll start treating the input as commands. */ worker->io = io_add(worker->fd_in, IO_READ, proxy_client_worker_read_to_eof, worker); worker->msg_get_data.input = i_stream_create_dot(worker->input, FALSE); } }
int pop3c_client_cmd_stream(struct pop3c_client *client, const char *cmd, struct istream **input_r, const char **error_r) { struct istream *inputs[2]; *input_r = NULL; /* read the +OK / -ERR */ if (pop3c_client_cmd_line(client, cmd, error_r) < 0) return -1; /* read the stream */ inputs[0] = i_stream_create_dot(client->input, TRUE); inputs[1] = NULL; client->dot_input = i_stream_create_seekable(inputs, POP3C_MAX_INBUF_SIZE, seekable_fd_callback, client); i_stream_unref(&inputs[0]); i_assert(client->io == NULL); client->io = io_add(client->fd, IO_READ, pop3c_client_dot_input, client); /* read any pending data from the stream */ pop3c_client_dot_input(client); if (!client->dot_input->eof) pop3c_client_run(client); if (client->input == NULL) { i_assert(client->io == NULL); i_stream_destroy(&client->dot_input); *error_r = "Disconnected"; return -1; } io_remove(&client->io); i_stream_seek(client->dot_input, 0); /* if this stream is used by some filter stream, make the filter stream blocking */ client->dot_input->blocking = TRUE; *input_r = client->dot_input; client->dot_input = NULL; return 0; }
static void print_connection_released(void) { struct doveadm_server *server = printing_conn->server; struct server_connection *const *conns; unsigned int i, count; printing_conn = NULL; conns = array_get(&server->connections, &count); for (i = 0; i < count; i++) { if (conns[i]->io != NULL) continue; conns[i]->io = io_add(conns[i]->fd, IO_READ, server_connection_input, conns[i]); server_connection_input(conns[i]); if (printing_conn != NULL) break; } }
static int master_login_auth_connect(struct master_login_auth *auth) { int fd; i_assert(auth->fd == -1); fd = net_connect_unix_with_retries(auth->auth_socket_path, 1000); if (fd == -1) { i_error("net_connect_unix(%s) failed: %m", auth->auth_socket_path); return -1; } auth->fd = fd; auth->input = i_stream_create_fd(fd, AUTH_MAX_INBUF_SIZE, FALSE); auth->output = o_stream_create_fd(fd, (size_t)-1, FALSE); o_stream_set_no_error_handling(auth->output, TRUE); auth->io = io_add(fd, IO_READ, master_login_auth_input, auth); return 0; }
struct notify_connection * notify_connection_create(int fd, struct replicator_queue *queue) { struct notify_connection *conn; i_assert(fd >= 0); conn = i_new(struct notify_connection, 1); conn->refcount = 1; conn->queue = queue; conn->fd = fd; conn->input = i_stream_create_fd(fd, MAX_INBUF_SIZE, FALSE); conn->output = o_stream_create_fd(fd, (size_t)-1, FALSE); o_stream_set_no_error_handling(conn->output, TRUE); conn->io = io_add(fd, IO_READ, notify_connection_input, conn); conn->queue = queue; DLLIST_PREPEND(&connections, conn); return conn; }
struct login_connection * login_connection_init(struct director *dir, int fd, struct auth_connection *auth, bool userdb) { struct login_connection *conn; conn = i_new(struct login_connection, 1); conn->refcount = 1; conn->fd = fd; conn->auth = auth; conn->dir = dir; conn->output = o_stream_create_fd(conn->fd, (size_t)-1, FALSE); o_stream_set_no_error_handling(conn->output, TRUE); conn->io = io_add(conn->fd, IO_READ, login_connection_input, conn); conn->userdb = userdb; auth_connection_set_callback(conn->auth, auth_input_line, conn); DLLIST_PREPEND(&login_connections, conn); return conn; }
static void user_callback(enum userdb_result result, struct auth_request *auth_request) { struct auth_postfix_connection *conn = auth_request->context; string_t *str; const char *value; if (auth_request->userdb_lookup_tempfailed) result = USERDB_RESULT_INTERNAL_FAILURE; str = t_str_new(128); switch (result) { case USERDB_RESULT_INTERNAL_FAILURE: if (auth_request->userdb_lookup_tempfailed) value = auth_fields_find(auth_request->userdb_reply, "reason"); else value = NULL; str_printfa(str, "400 %s", value != NULL ? value: "Internal failure"); break; case USERDB_RESULT_USER_UNKNOWN: str_append(str, "500 User not found"); break; case USERDB_RESULT_OK: str_append(str, "200 1"); break; } if (conn->auth->set->debug) i_debug("postfix out: %s", str_c(str)); str_append_c(str, '\n'); o_stream_nsend(conn->output, str_data(str), str_len(str)); i_assert(conn->io == NULL); if (!conn->destroyed) conn->io = io_add(conn->fd, IO_READ, postfix_input, conn); auth_request_unref(&auth_request); auth_postfix_connection_unref(&conn); }
static void pop3c_client_connected(struct pop3c_client *client) { int err; err = net_geterror(client->fd); if (err != 0) { i_error("pop3c(%s): connect(%s, %u) failed: %s", client->set.host, net_ip2addr(&client->ip), client->set.port, strerror(err)); pop3c_client_disconnect(client); return; } io_remove(&client->io); client->io = io_add(client->fd, IO_READ, pop3c_client_prelogin_input, client); if (client->set.ssl_mode == POP3C_CLIENT_SSL_MODE_IMMEDIATE) { if (pop3c_client_ssl_init(client) < 0) pop3c_client_disconnect(client); } }
struct client_connection * client_connection_create(int fd, int listen_fd, bool ssl) { struct client_connection *conn; const char *ip; pool_t pool; pool = pool_alloconly_create("doveadm client", 1024*16); conn = p_new(pool, struct client_connection, 1); conn->pool = pool; conn->fd = fd; conn->io = io_add(fd, IO_READ, client_connection_input, conn); conn->input = i_stream_create_fd(fd, MAX_INBUF_SIZE, FALSE); conn->output = o_stream_create_fd(fd, (size_t)-1, FALSE); o_stream_set_no_error_handling(conn->output, TRUE); (void)net_getsockname(fd, &conn->local_ip, &conn->local_port); (void)net_getpeername(fd, &conn->remote_ip, &conn->remote_port); i_stream_set_name(conn->input, net_ip2addr(&conn->remote_ip)); o_stream_set_name(conn->output, net_ip2addr(&conn->remote_ip)); ip = net_ip2addr(&conn->remote_ip); if (ip[0] != '\0') i_set_failure_prefix("doveadm(%s): ", ip); if (client_connection_read_settings(conn) < 0) { client_connection_destroy(&conn); return NULL; } if (ssl) { if (client_connection_init_ssl(conn) < 0) { client_connection_destroy(&conn); return NULL; } } client_connection_send_auth_handshake(conn, listen_fd); return conn; }
static int login_proxy_connect(struct login_proxy *proxy) { struct login_proxy_record *rec = proxy->state_rec; if (rec->last_success.tv_sec == 0) { /* first connect to this IP. don't start immediately failing the check below. */ rec->last_success.tv_sec = ioloop_timeval.tv_sec - 1; } if (timeval_cmp(&rec->last_failure, &rec->last_success) > 0 && rec->last_failure.tv_sec - rec->last_success.tv_sec > PROXY_IMMEDIATE_FAILURE_SECS && rec->num_waiting_connections != 0) { /* the server is down. fail immediately */ i_error("proxy(%s): Host %s:%u is down", proxy->client->virtual_user, proxy->host, proxy->port); login_proxy_free(&proxy); return -1; } proxy->server_fd = net_connect_ip(&proxy->ip, proxy->port, proxy->source_ip.family == 0 ? NULL : &proxy->source_ip); if (proxy->server_fd == -1) { proxy_log_connect_error(proxy); login_proxy_free(&proxy); return -1; } proxy->server_io = io_add(proxy->server_fd, IO_WRITE, proxy_wait_connect, proxy); if (proxy->connect_timeout_msecs != 0) { proxy->to = timeout_add(proxy->connect_timeout_msecs, proxy_connect_timeout, proxy); } proxy->num_waiting_connections_updated = FALSE; proxy->state_rec = rec; proxy->state_rec->num_waiting_connections++; return 0; }
static int fts_indexer_more_int(struct fts_indexer_context *ctx) { struct ioloop *ioloop; struct io *io; struct timeout *to; int ret; if ((ret = fts_indexer_input(ctx)) != 0) return ret; /* wait for a while for the reply. FIXME: once search API supports asynchronous waits, get rid of this wait and use the mail IO loop */ ioloop = io_loop_create(); io = io_add(ctx->fd, IO_READ, io_loop_stop, ioloop); to = timeout_add_short(INDEXER_WAIT_MSECS, io_loop_stop, ioloop); io_loop_run(ioloop); io_remove(&io); timeout_remove(&to); io_loop_destroy(&ioloop); return fts_indexer_input(ctx); }
int io_socket_connect(io_atom *io, io_proc proc, socket_addr remote, int flags) { int err; io->fd = io_socket_connect_fd(remote); if(io->fd < 0) { return -1; } io->proc = proc; err = io_add(io, flags); if(err < 0) { goto bail; } return io->fd; bail: close(io->fd); io->fd = -1; return -1; }
static int ldap_connection_connect(struct ldap_connection *conn) { const char *error; int fd; Sockbuf *sb; bool finished; if (conn->conn == NULL) { /* try to reconnect after disconnection */ if (ldap_connection_setup(conn, &error) < 0) i_error("%s", error); } pool_t pool = pool_alloconly_create(MEMPOOL_GROWING "ldap bind", 128); struct ldap_op_queue_entry *req = p_new(pool, struct ldap_op_queue_entry, 1); req->pool = pool; req->internal_response_cb = ldap_connection_connect_parse; req->timeout_secs = conn->set.timeout_secs; if (ldap_connect_next_message(conn, req, &finished) != LDAP_SUCCESS || conn->conn == NULL) { pool_unref(&pool); return -1; } conn->pending++; aqueue_append(conn->request_queue, &req); /* start timeout */ if (req->timeout_secs > 0) req->to_abort = timeout_add(req->timeout_secs * 1000, ldap_connection_abort_request, req); ldap_get_option(conn->conn, LDAP_OPT_SOCKBUF, &sb); ber_sockbuf_ctrl(sb, LBER_SB_OPT_GET_FD, &fd); conn->io = io_add(fd, IO_READ, ldap_connection_read_more, conn); if (conn->set.max_idle_time_secs > 0) conn->to_disconnect = timeout_add(conn->set.max_idle_time_secs * 1000, ldap_connection_kill, conn); return 0; }
int io_socket_listen(io_atom *io, io_proc proc, socket_addr local) { struct sockaddr_in sin; if((io->fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { return -1; } if(set_nonblock(io->fd) < 0) { close(io->fd); return -1; } memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_addr = local.addr; sin.sin_port = htons(local.port); if(bind(io->fd, (struct sockaddr*)&sin, sizeof(sin)) < 0) { close(io->fd); return -1; } // NOTE: if we're dropping connection requests under load, we // may need to tune the second parameter to listen. if (listen(io->fd, STD_LISTEN_SIZE) == -1) { close(io->fd); return -1; } io->proc = proc; if(io_add(io, IO_READ) < 0) { close(io->fd); return -1; } return io->fd; }
static void ssl_output(struct ssl_proxy *proxy) { int sent; sent = net_transmit(proxy->fd_plain, proxy->outbuf_plain + proxy->outbuf_pos_plain, proxy->send_left_plain); if (sent < 0) { /* disconnected */ ssl_proxy_destroy(proxy); return; } proxy->send_left_plain -= sent; proxy->outbuf_pos_plain += sent; if (proxy->send_left_plain > 0) return; /* everything is sent, start reading again */ io_remove(proxy->io_ssl); proxy->io_ssl = io_add(proxy->fd_ssl, IO_READ, ssl_input, proxy); }
int server_connection_create(struct doveadm_server *server, struct server_connection **conn_r) { #define DOVEADM_SERVER_HANDSHAKE "VERSION\tdoveadm-server\t1\t0\n" struct server_connection *conn; pool_t pool; pool = pool_alloconly_create("doveadm server connection", 1024*16); conn = p_new(pool, struct server_connection, 1); conn->pool = pool; conn->server = server; conn->fd = doveadm_connect_with_default_port(server->name, doveadm_settings->doveadm_port); net_set_nonblock(conn->fd, TRUE); conn->io = io_add(conn->fd, IO_READ, server_connection_input, conn); conn->input = i_stream_create_fd(conn->fd, MAX_INBUF_SIZE); conn->output = o_stream_create_fd(conn->fd, (size_t)-1); o_stream_set_flush_callback(conn->output, server_connection_output, conn); i_stream_set_name(conn->input, server->name); o_stream_set_name(conn->output, server->name); array_append(&conn->server->connections, &conn, 1); if (server_connection_read_settings(conn) < 0 || server_connection_init_ssl(conn) < 0) { server_connection_destroy(&conn); return -1; } o_stream_set_no_error_handling(conn->output, TRUE); conn->state = SERVER_REPLY_STATE_DONE; o_stream_nsend_str(conn->output, DOVEADM_SERVER_HANDSHAKE); *conn_r = conn; return 0; }
struct access_lookup * access_lookup(const char *path, int client_fd, const char *daemon_name, access_lookup_callback_t *callback, void *context) { struct access_lookup *lookup; const char *cmd; ssize_t ret; int fd; fd = net_connect_unix(path); if (fd == -1) { i_error("connect(%s) failed: %m", path); return NULL; } cmd = t_strconcat(daemon_name, "\n", NULL); ret = fd_send(fd, client_fd, cmd, strlen(cmd)); if (ret != (ssize_t)strlen(cmd)) { if (ret < 0) i_error("fd_send(%s) failed: %m", path); else i_error("fd_send(%s) didn't write enough bytes", path); i_close_fd(&fd); return NULL; } lookup = i_new(struct access_lookup, 1); lookup->refcount = 1; lookup->fd = fd; lookup->path = i_strdup(path); lookup->io = io_add(fd, IO_READ, access_lookup_input, lookup); lookup->to = timeout_add(ACCESS_LOOKUP_TIMEOUT_MSECS, access_lookup_timeout, lookup); lookup->callback = callback; lookup->context = context; return lookup; }
static struct client *client_create(int fd) { struct client *client; /* always use nonblocking I/O */ net_set_nonblock(fd, TRUE); client = i_new(struct client, 1); i_array_init(&client->access_apps, 16); client->fd_in = -1; client->fd_out = -1; client->fd_ctrl = fd; client->access_anonymous = TRUE; /* default until overridden */ client->ctrl_io = io_add(fd, IO_READ, client_ctrl_input, client); client->to_idle = timeout_add(CLIENT_IDLE_TIMEOUT_MSECS, client_idle_timeout, client); imap_urlauth_worker_client_count++; DLLIST_PREPEND(&imap_urlauth_worker_clients, client); imap_urlauth_worker_refresh_proctitle(); return client; }
static void plain_input(struct ssl_proxy *proxy) { char buf[1024]; ssize_t rcvd, sent; rcvd = net_receive(proxy->fd_plain, buf, sizeof(buf)); if (rcvd < 0) { /* disconnected */ gnutls_bye(proxy->session, 1); ssl_proxy_destroy(proxy); return; } sent = proxy_send_ssl(proxy, buf, (size_t)rcvd); if (sent < 0 || sent == rcvd) return; /* everything wasn't sent - don't read anything until we've sent it all */ proxy->send_left_ssl = rcvd - sent; io_remove(proxy->io_plain); proxy->io_plain = io_add(proxy->fd_ssl, IO_WRITE, plain_output, proxy); }
static int pop3c_client_read_line(struct pop3c_client *client, const char **line_r, const char **error_r) { i_assert(client->io == NULL); i_assert(client->input_line == NULL); client->io = io_add(client->fd, IO_READ, pop3c_client_input_reply, client); pop3c_client_input_reply(client); if (client->input_line == NULL && client->input != NULL) pop3c_client_run(client); if (client->input_line == NULL) { i_assert(client->io == NULL); *error_r = "Disconnected"; return -1; } io_remove(&client->io); *line_r = t_strdup(client->input_line); client->input_line = NULL; return 0; }
static void sasl_callback(struct client *client, enum sasl_server_reply sasl_reply, const char *data, const char *const *args) { struct client_auth_reply reply; i_assert(!client->destroyed || sasl_reply == SASL_SERVER_REPLY_AUTH_ABORTED || sasl_reply == SASL_SERVER_REPLY_MASTER_FAILED); switch (sasl_reply) { case SASL_SERVER_REPLY_SUCCESS: if (client->to_auth_waiting != NULL) timeout_remove(&client->to_auth_waiting); if (args != NULL) { client_auth_parse_args(client, args, &reply); if (client_auth_handle_reply(client, &reply, TRUE)) break; } client_auth_result(client, CLIENT_AUTH_RESULT_SUCCESS, NULL, NULL); client_destroy_success(client, "Login"); break; case SASL_SERVER_REPLY_AUTH_FAILED: case SASL_SERVER_REPLY_AUTH_ABORTED: if (client->to_auth_waiting != NULL) timeout_remove(&client->to_auth_waiting); if (args != NULL) { client_auth_parse_args(client, args, &reply); reply.nologin = TRUE; if (client_auth_handle_reply(client, &reply, FALSE)) break; } if (sasl_reply == SASL_SERVER_REPLY_AUTH_ABORTED) { client_auth_result(client, CLIENT_AUTH_RESULT_ABORTED, NULL, "Authentication aborted by client."); } else if (data == NULL) { client_auth_result(client, CLIENT_AUTH_RESULT_AUTHFAILED, NULL, AUTH_FAILED_MSG); } else { client_auth_result(client, CLIENT_AUTH_RESULT_AUTHFAILED_REASON, NULL, data); } if (!client->destroyed) client_auth_failed(client); break; case SASL_SERVER_REPLY_MASTER_FAILED: if (data != NULL) { /* authentication itself succeeded, we just hit some internal failure. */ client_auth_result(client, CLIENT_AUTH_RESULT_TEMPFAIL, NULL, data); } /* the fd may still be hanging somewhere in kernel or another process. make sure the client gets disconnected. */ if (shutdown(client->fd, SHUT_RDWR) < 0 && errno != ENOTCONN) i_error("shutdown() failed: %m"); if (data == NULL) client_destroy_internal_failure(client); else client_destroy_success(client, data); break; case SASL_SERVER_REPLY_CONTINUE: i_assert(client->v.auth_send_challenge != NULL); client->v.auth_send_challenge(client, data); if (client->to_auth_waiting != NULL) timeout_remove(&client->to_auth_waiting); if (client->auth_response != NULL) str_truncate(client->auth_response, 0); i_assert(client->io == NULL); client->auth_waiting = TRUE; client->io = io_add(client->fd, IO_READ, client_auth_input, client); client_auth_input(client); return; } client_unref(&client); }