Пример #1
0
void login_proxy_detach(struct login_proxy *proxy)
{
	struct client *client = proxy->client;
	const unsigned char *data;
	size_t size;

	i_assert(proxy->client_fd == -1);
	i_assert(proxy->server_input != NULL);
	i_assert(proxy->server_output != NULL);

	if (proxy->to != NULL)
		timeout_remove(&proxy->to);

	proxy->client_fd = i_stream_get_fd(client->input);
	proxy->client_input = client->input;
	proxy->client_output = client->output;

	i_stream_set_persistent_buffers(client->input, FALSE);
	o_stream_set_max_buffer_size(client->output, (size_t)-1);
	o_stream_set_flush_callback(client->output, proxy_client_output, proxy);
	client->input = NULL;
	client->output = NULL;

	/* send all pending client input to proxy */
	data = i_stream_get_data(proxy->client_input, &size);
	if (size != 0)
		o_stream_nsend(proxy->server_output, data, size);

	/* from now on, just do dummy proxying */
	io_remove(&proxy->server_io);
	proxy->server_io =
		io_add(proxy->server_fd, IO_READ, server_input, proxy);
	proxy->client_io =
		io_add_istream(proxy->client_input, proxy_client_input, proxy);
	o_stream_set_flush_callback(proxy->server_output, server_output, proxy);
	i_stream_destroy(&proxy->server_input);

	if (proxy->notify_refresh_secs != 0) {
		proxy->to_notify =
			timeout_add(proxy->notify_refresh_secs * 1000,
				    login_proxy_notify, proxy);
	}

	proxy->callback = NULL;

	if (login_proxy_ipc_server == NULL) {
		login_proxy_ipc_server =
			ipc_server_init(LOGIN_PROXY_IPC_PATH,
					LOGIN_PROXY_IPC_NAME,
					login_proxy_ipc_cmd);
	}

	DLLIST_REMOVE(&login_proxies_pending, proxy);
	DLLIST_PREPEND(&login_proxies, proxy);

	client->fd = -1;
	client->login_proxy = NULL;
}
int script_client_run(struct script_client *sclient)
{
	int ret;

	sclient->ioloop = io_loop_create();

	if ( script_client_connect(sclient) >= 0 ) {
		/* run output */
		ret = 1;		
		if ( sclient->script_output != NULL &&
			(ret=o_stream_flush(sclient->script_output)) == 0 ) {
			o_stream_set_flush_callback
				(sclient->script_output, script_client_script_output, sclient);
		}

		/* run i/o event loop */
		if ( ret < 0 ) {
			sclient->error = SCRIPT_CLIENT_ERROR_IO;
		} else if ( sclient->io != NULL || ret == 0 ) {
			io_loop_run(sclient->ioloop);
		}

		/* finished */
		script_client_disconnect(sclient, FALSE);
	}

	io_loop_destroy(&sclient->ioloop);

	if ( sclient->error != SCRIPT_CLIENT_ERROR_NONE )
		return -1;

	return sclient->exit_code;
}
Пример #3
0
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;
}
Пример #4
0
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);
}
Пример #5
0
struct ostream *openssl_o_stream_create_ssl(struct ssl_iostream *ssl_io)
{
	struct ssl_ostream *sstream;

	ssl_io->refcount++;

	sstream = i_new(struct ssl_ostream, 1);
	sstream->ssl_io = ssl_io;
	sstream->ostream.max_buffer_size =
		ssl_io->plain_output->real_stream->max_buffer_size;
	sstream->ostream.iostream.close = o_stream_ssl_close;
	sstream->ostream.iostream.destroy = o_stream_ssl_destroy;
	sstream->ostream.sendv = o_stream_ssl_sendv;
	sstream->ostream.flush = o_stream_ssl_flush;
	sstream->ostream.switch_ioloop = o_stream_ssl_switch_ioloop;

	sstream->ostream.flush_pending = o_stream_ssl_flush_pending;
	sstream->ostream.iostream.set_max_buffer_size =
		o_stream_ssl_set_max_buffer_size;

	sstream->ostream.callback = ssl_io->plain_output->real_stream->callback;
	sstream->ostream.context = ssl_io->plain_output->real_stream->context;
	o_stream_set_flush_callback(ssl_io->plain_output,
				    plain_flush_callback, sstream);

	return o_stream_create(&sstream->ostream, NULL,
			       o_stream_get_fd(ssl_io->plain_output));
}
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);
	}
}
Пример #7
0
static int lmtp_client_connect(struct lmtp_client *client)
{
	i_assert(client->fd == -1);

	client->times.connect_started = ioloop_timeval;

	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);
	client->output = o_stream_create_fd(client->fd, (size_t)-1);
	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);
	if (client->set.timeout_secs > 0) {
		client->to = timeout_add(client->set.timeout_secs*1000,
					 lmtp_client_connect_timeout, client);
	}
	return 0;
}
Пример #8
0
static void
o_stream_default_set_flush_callback(struct ostream_private *_stream,
				    stream_flush_callback_t *callback,
				    void *context)
{
	if (_stream->parent != NULL)
		o_stream_set_flush_callback(_stream->parent, callback, context);

	_stream->callback = callback;
	_stream->context = context;
}
Пример #9
0
static void cmd_setmetadata_deinit(struct imap_setmetadata_context *ctx)
{
    o_stream_set_flush_callback(ctx->cmd->client->output,
                                client_output, ctx->cmd->client);

    ctx->cmd->client->input_lock = NULL;
    imap_parser_unref(&ctx->parser);
    if (ctx->trans != NULL)
        imap_metadata_transaction_rollback(&ctx->trans);
    if (ctx->box != NULL && ctx->box != ctx->cmd->client->mailbox)
        mailbox_free(&ctx->box);
    i_free(ctx->entry_name);
}
Пример #10
0
static void cmd_putscript_finish(struct cmd_putscript_context *ctx)
{
	managesieve_parser_destroy(&ctx->save_parser);

	io_remove(&ctx->client->io);
	o_stream_set_flush_callback(ctx->client->output,
				    client_output, ctx->client);

	if (ctx->save_ctx != NULL)
	{
		ctx->client->input_skip_line = TRUE;
		sieve_storage_save_cancel(&ctx->save_ctx);
	}
}
Пример #11
0
static void client_handle(int fd)
{
	struct ostream *output;

	output = o_stream_create_fd(fd, (size_t)-1, TRUE);
	o_stream_send(output, ssl_params->data, ssl_params->used);

	if (o_stream_get_buffer_used_size(output) == 0)
		client_deinit(output);
	else {
		o_stream_set_flush_callback(output, client_output_flush,
					    output);
	}
}
Пример #12
0
struct client *client_create(int fd)
{
	struct client *client;

	client = i_new(struct client, 1);
	client->fd = fd;
	client->io = io_add(fd, IO_READ, client_input, client);
	client->input = i_stream_create_fd(fd, MAX_INBUF_SIZE, FALSE);
	client->output = o_stream_create_fd(fd, (size_t)-1, FALSE);
	o_stream_set_no_error_handling(client->output, TRUE);
	o_stream_set_flush_callback(client->output, client_output, client);
	client->cmd_pool = pool_alloconly_create("cmd pool", 1024);

	DLLIST_PREPEND(&clients, client);
	return client;
}
Пример #13
0
static struct client *
client_create_standalone(const char *access_user,
			 const char *const *access_applications,
			 int fd_in, int fd_out, bool debug)
{
	struct client *client;

	/* always use nonblocking I/O */
	net_set_nonblock(fd_in, TRUE);
	net_set_nonblock(fd_out, TRUE);

	client = i_new(struct client, 1);
	i_array_init(&client->access_apps, 16);
	client->fd_in = fd_in;
	client->fd_out = fd_out;
	client->fd_ctrl = -1;

	if (access_user != NULL && *access_user != '\0')
		client->access_user = i_strdup(access_user);
	else {
		client->access_user = i_strdup("anonymous");
		client->access_anonymous = TRUE;
	}
	if (access_applications != NULL) {
		const char *const *apps = access_applications;
		for (; *apps != NULL; apps++) {
			char *app = i_strdup(*apps);
			array_append(&client->access_apps, &app, 1);
		}
	}
	client->debug = debug;

	client->input = i_stream_create_fd(fd_in, MAX_INBUF_SIZE, FALSE);
	client->output = o_stream_create_fd(fd_out, (size_t)-1, FALSE);
	client->io = io_add(fd_in, IO_READ, client_input, client);
	client->to_idle = timeout_add(CLIENT_IDLE_TIMEOUT_MSECS,
				      client_idle_timeout, client);
	o_stream_set_flush_callback(client->output, client_output, client);

	imap_urlauth_worker_client_count++;
	DLLIST_PREPEND(&imap_urlauth_worker_clients, client);

	i_set_failure_prefix("imap-urlauth[%s](%s): ",
			     my_pid, client->access_user);
	return client;
}
Пример #14
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_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;
}
Пример #15
0
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);
}
Пример #16
0
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;
}
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);
}
Пример #18
0
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);
}
Пример #19
0
void iostream_pump_start(struct iostream_pump *pump)
{
	i_assert(pump != NULL);
	i_assert(pump->callback != NULL);

	/* add flush handler */
	if (!pump->output->blocking) {
		o_stream_set_flush_callback(pump->output,
					    iostream_pump_flush, pump);
	}

	/* make IO objects */
	if (pump->input->blocking) {
		i_assert(!pump->output->blocking);
		o_stream_set_flush_pending(pump->output, TRUE);
	} else {
		pump->io = io_add_istream(pump->input,
					  iostream_pump_copy, pump);
		io_set_pending(pump->io);
	}
}
Пример #20
0
int program_client_run(struct program_client *pclient)
{
	int ret;

	/* reset */
	pclient->disconnected = FALSE;
	pclient->exit_code = 1;
	pclient->error = PROGRAM_CLIENT_ERROR_NONE;

	pclient->ioloop = io_loop_create();

	if ( (ret=program_client_connect(pclient)) >= 0 ) {
		/* run output */
		if ( ret > 0 && pclient->program_output != NULL &&
			(ret=o_stream_flush(pclient->program_output)) == 0 ) {
			o_stream_set_flush_callback
				(pclient->program_output, program_client_program_output, pclient);
		}

		/* run i/o event loop */
		if ( ret < 0 ) {
			pclient->error = PROGRAM_CLIENT_ERROR_IO;
		} else if ( !pclient->disconnected &&
			(ret == 0 || program_client_input_pending(pclient)) ) {
			io_loop_run(pclient->ioloop);
		}

		/* finished */
		program_client_disconnect(pclient, FALSE);
	}

	io_loop_destroy(&pclient->ioloop);

	if ( pclient->error != PROGRAM_CLIENT_ERROR_NONE )
		return -1;

	return pclient->exit_code;
}
Пример #21
0
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;
}
Пример #22
0
int program_client_connected
(struct program_client *pclient)
{
	int ret = 1;

	pclient->start_time = ioloop_time;
	if (pclient->to != NULL)
		timeout_remove(&pclient->to);
	if ( pclient->set.input_idle_timeout_secs != 0 ) {
		pclient->to = timeout_add(pclient->set.input_idle_timeout_secs*1000,
      program_client_timeout, pclient);
	}

	/* run output */
	if ( pclient->program_output != NULL &&
		(ret=program_client_program_output(pclient)) == 0 ) {
		if ( pclient->program_output != NULL ) {
			o_stream_set_flush_callback
				(pclient->program_output, program_client_program_output, pclient);
		}
	}

	return ret;
}
int script_client_script_connected
(struct script_client *sclient)
{
	int ret = 1;

	sclient->start_time = ioloop_time;
	if (sclient->to != NULL)
		timeout_remove(&sclient->to);
	if ( sclient->set->input_idle_timeout_secs != 0 ) {
		sclient->to = timeout_add(sclient->set->input_idle_timeout_secs*1000,
      script_client_timeout, sclient);
	}

	/* run output */
	if ( sclient->script_output != NULL &&
		(ret=script_client_script_output(sclient)) == 0 ) {
		if ( sclient->script_output != NULL ) {
			o_stream_set_flush_callback
				(sclient->script_output, script_client_script_output, sclient);
		}
	}

	return ret;
}
Пример #24
0
struct client *client_create(int fd_in, int fd_out, const char *session_id,
			     struct mail_user *user,
			     struct mail_storage_service_user *service_user,
			     const struct imap_settings *set)
{
	const struct mail_storage_settings *mail_set;
	struct client *client;
	const char *ident;
	pool_t pool;
	bool explicit_capability = FALSE;

	/* always use nonblocking I/O */
	net_set_nonblock(fd_in, TRUE);
	net_set_nonblock(fd_out, TRUE);

	pool = pool_alloconly_create("imap client", 2048);
	client = p_new(pool, struct client, 1);
	client->pool = pool;
	client->v = imap_client_vfuncs;
	client->set = set;
	client->service_user = service_user;
	client->session_id = p_strdup(pool, session_id);
	client->fd_in = fd_in;
	client->fd_out = fd_out;
	client->input = i_stream_create_fd(fd_in,
					   set->imap_max_line_length, FALSE);
	client->output = o_stream_create_fd(fd_out, (size_t)-1, FALSE);
	o_stream_set_no_error_handling(client->output, TRUE);
	i_stream_set_name(client->input, "<imap client>");
	o_stream_set_name(client->output, "<imap client>");

	o_stream_set_flush_callback(client->output, client_output, client);

	p_array_init(&client->module_contexts, client->pool, 5);
	client->io = io_add_istream(client->input, client_input, client);
        client->last_input = ioloop_time;
	client->to_idle = timeout_add(CLIENT_IDLE_TIMEOUT_MSECS,
				      client_idle_timeout, client);

	client->command_pool =
		pool_alloconly_create(MEMPOOL_GROWING"client command", 1024*2);
	client->user = user;
	client->notify_count_changes = TRUE;
	client->notify_flag_changes = TRUE;

	mail_namespaces_set_storage_callbacks(user->namespaces,
					      &mail_storage_callbacks, client);

	client->capability_string =
		str_new(client->pool, sizeof(CAPABILITY_STRING)+64);

	if (*set->imap_capability == '\0')
		str_append(client->capability_string, CAPABILITY_STRING);
	else if (*set->imap_capability != '+') {
		explicit_capability = TRUE;
		str_append(client->capability_string, set->imap_capability);
	} else {
		str_append(client->capability_string, CAPABILITY_STRING);
		str_append_c(client->capability_string, ' ');
		str_append(client->capability_string, set->imap_capability + 1);
	}
	if (user->fuzzy_search && !explicit_capability) {
		/* Enable FUZZY capability only when it actually has
		   a chance of working */
		str_append(client->capability_string, " SEARCH=FUZZY");
	}

	mail_set = mail_user_set_get_storage_set(user);
	if (mail_set->mailbox_list_index && !explicit_capability) {
		/* NOTIFY is enabled only when mailbox list indexes are
		   enabled, although even that doesn't necessarily guarantee
		   it always */
		str_append(client->capability_string, " NOTIFY");
	}

	if (*set->imap_urlauth_host != '\0' &&
	    *mail_set->mail_attribute_dict != '\0') {
		/* Enable URLAUTH capability only when dict is
		   configured correctly */
		client_init_urlauth(client);
		if (!explicit_capability)
			str_append(client->capability_string, " URLAUTH URLAUTH=BINARY");
	}
	if (set->imap_metadata && *mail_set->mail_attribute_dict != '\0') {
		client->imap_metadata_enabled = TRUE;
		if (!explicit_capability)
			str_append(client->capability_string, " METADATA");
	}
	if (!explicit_capability && user_has_special_use_mailboxes(user)) {
		/* Advertise SPECIAL-USE only if there are actually some
		   SPECIAL-USE flags in mailbox configuration. */
		str_append(client->capability_string, " SPECIAL-USE");
	}

	ident = mail_user_get_anvil_userip_ident(client->user);
	if (ident != NULL) {
		master_service_anvil_send(master_service, t_strconcat(
			"CONNECT\t", my_pid, "\timap/", ident, "\n", NULL));
		client->anvil_sent = TRUE;
	}

	imap_client_count++;
	DLLIST_PREPEND(&imap_clients, client);
	if (hook_client_created != NULL)
		hook_client_created(&client);

	imap_refresh_proctitle();
	return client;
}
Пример #25
0
static void client_ctrl_input(struct client *client)
{
	const char *const *args;
	const char *line;
	int ret;

	timeout_reset(client->to_idle);

	if (client->fd_in == -1 || client->fd_out == -1) {
		if ((ret = client_ctrl_read_fds(client)) <= 0) {
			if (ret < 0)
				client_abort(client, "FD Transfer failed");
			return;
		}
	}

	switch (i_stream_read(client->ctrl_input)) {
	case -1:
		/* disconnected */
		client_destroy(client);
		return;
	case -2:
		/* line too long, kill it */
		client_abort(client,
			     "Control session aborted: Input line too long");
		return;
	}

	if (!client->version_received) {
		if ((line = i_stream_next_line(client->ctrl_input)) == NULL)
			return;

		if (!version_string_verify(line, "imap-urlauth-worker",
				IMAP_URLAUTH_WORKER_PROTOCOL_MAJOR_VERSION)) {
			i_error("imap-urlauth-worker client not compatible with this server "
				"(mixed old and new binaries?) %s", line);
			client_abort(client, "Control session aborted: Version mismatch");
			return;
		}

		client->version_received = TRUE;
		if (o_stream_send_str(client->ctrl_output, "OK\n") < 0) {
			client_destroy(client);
			return;
		}
	}

	if (client->access_received) {
		client_abort(client, "Control session aborted: Unexpected input");
		return;
	}

	if ((line = i_stream_next_line(client->ctrl_input)) == NULL)
		return;

	args = t_strsplit_tabescaped(line);
	if (*args == NULL || strcmp(*args, "ACCESS") != 0) {
		i_error("Invalid control command: %s", str_sanitize(line, 80));
		client_abort(client, "Control session aborted: Invalid command");
		return;
	}
	args++;
	if (*args == NULL) {
		i_error("Invalid ACCESS command: %s", str_sanitize(line, 80));
		client_abort(client, "Control session aborted: Invalid command");
		return;
	}

	i_assert(client->access_user == NULL);
	if (**args != '\0') {
		client->access_user = i_strdup(*args);
		client->access_anonymous = FALSE;
	} else {
		client->access_user = i_strdup("anonymous");
		client->access_anonymous = TRUE;
	}
	i_set_failure_prefix("imap-urlauth[%s](%s): ",
			     my_pid, client->access_user);

	args++;
	while (*args != NULL) {
		/* debug */
		if (strcasecmp(*args, "debug") == 0) {
			client->debug = TRUE;
		/* apps=<access-application>[,<access-application,...] */
		} else if (strncasecmp(*args, "apps=", 5) == 0 &&
			   (*args)[5] != '\0') {
			const char *const *apps = t_strsplit(*args+5, ",");

			while (*apps != NULL) {
				char *app = i_strdup(*apps);

				array_append(&client->access_apps, &app, 1);
				if (client->debug) {
					i_debug("User %s has URLAUTH %s access",
						client->access_user, app);
				}
				apps++;
			}
		} else {
			i_error("Invalid ACCESS parameter: %s", str_sanitize(*args, 80));
			client_abort(client, "Control session aborted: Invalid command");
			return;
		} 
		args++;
	}

	client->access_received = TRUE;

	if (o_stream_send_str(client->ctrl_output, "OK\n") < 0) {
		client_destroy(client);
		return;
	}

	client->input = i_stream_create_fd(client->fd_in, MAX_INBUF_SIZE, FALSE);
	client->output = o_stream_create_fd(client->fd_out, (size_t)-1, FALSE); 
	client->io = io_add(client->fd_in, IO_READ, client_input, client);
	o_stream_set_flush_callback(client->output, client_output, client);

	if (client->debug) {
		i_debug("Worker activated for access by user %s",
			client->access_user);
	}
}