Example #1
0
static void io_loop_handle_timeouts_real(struct ioloop *ioloop)
{
	struct priorityq_item *item;
	struct timeval tv, tv_call;
	unsigned int t_id;

	if (gettimeofday(&ioloop_timeval, NULL) < 0)
		i_fatal("gettimeofday(): %m");

	/* Don't bother comparing usecs. */
	if (unlikely(ioloop_time > ioloop_timeval.tv_sec)) {
		/* time moved backwards */
		io_loops_timeouts_update(-(long)(ioloop_time -
						 ioloop_timeval.tv_sec));
		ioloop->time_moved_callback(ioloop_time,
					    ioloop_timeval.tv_sec);
		/* the callback may have slept, so check the time again. */
		if (gettimeofday(&ioloop_timeval, NULL) < 0)
			i_fatal("gettimeofday(): %m");
	} else if (unlikely(ioloop_timeval.tv_sec >
			    ioloop->next_max_time)) {
		io_loops_timeouts_update(ioloop_timeval.tv_sec -
					ioloop->next_max_time);
		/* time moved forwards */
		ioloop->time_moved_callback(ioloop->next_max_time,
					    ioloop_timeval.tv_sec);
	}

	ioloop_time = ioloop_timeval.tv_sec;
	tv_call = ioloop_timeval;

	while ((item = priorityq_peek(ioloop->timeouts)) != NULL) {
		struct timeout *timeout = (struct timeout *)item;

		/* use tv_call to make sure we don't get to infinite loop in
		   case callbacks update ioloop_timeval. */
		if (timeout_get_wait_time(timeout, &tv, &tv_call) > 0)
			break;

		/* update timeout's next_run and reposition it in the queue */
		timeout_reset_timeval(timeout, &tv_call);

		if (timeout->log != NULL) {
			ioloop->cur_log = timeout->log;
			io_loop_log_ref(ioloop->cur_log);
			i_set_failure_prefix(timeout->log->prefix);
		}
                t_id = t_push();
		timeout->callback(timeout->context);
		if (t_pop() != t_id) {
			i_panic("Leaked a t_pop() call in timeout handler %p",
				(void *)timeout->callback);
		}
		if (ioloop->cur_log != NULL) {
			io_loop_log_unref(&ioloop->cur_log);
			i_set_failure_prefix(ioloop->default_log_prefix);
		}
	}
}
Example #2
0
static int
cmd_dsync_server_run(struct doveadm_mail_cmd_context *_ctx,
		     struct mail_user *user)
{
	struct dsync_cmd_context *ctx = (struct dsync_cmd_context *)_ctx;
	struct dsync_ibc *ibc;
	struct dsync_brain *brain;
	string_t *temp_prefix, *state_str = NULL;
	enum dsync_brain_sync_type sync_type;
	const char *name;

	if (_ctx->conn != NULL) {
		/* doveadm-server connection. start with a success reply.
		   after that follows the regular dsync protocol. */
		ctx->fd_in = ctx->fd_out = -1;
		ctx->input = _ctx->conn->input;
		ctx->output = _ctx->conn->output;
		o_stream_nsend(ctx->output, "\n+\n", 3);
		i_set_failure_prefix("dsync-server(%s): ", user->username);
		name = i_stream_get_name(ctx->input);
	} else {
		/* the log messages go via stderr to the remote dsync,
		   so the names are reversed */
		i_set_failure_prefix("dsync-remote(%s): ", user->username);
		name = "local";
	}

	doveadm_user_init_dsync(user);

	temp_prefix = t_str_new(64);
	mail_user_set_get_temp_prefix(temp_prefix, user->set);

	ibc = cmd_dsync_icb_stream_init(ctx, name, str_c(temp_prefix));
	brain = dsync_brain_slave_init(user, ibc, FALSE);

	io_loop_run(current_ioloop);

	if (ctx->replicator_notify) {
		state_str = t_str_new(128);
		dsync_brain_get_state(brain, state_str);
	}
	sync_type = dsync_brain_get_sync_type(brain);

	if (dsync_brain_deinit(&brain) < 0)
		_ctx->exit_code = EX_TEMPFAIL;
	dsync_ibc_deinit(&ibc);

	if (_ctx->conn != NULL) {
		/* make sure nothing more is written by the generic doveadm
		   connection code */
		o_stream_close(_ctx->conn->output);
	}

	if (ctx->replicator_notify && _ctx->exit_code == 0)
		dsync_replicator_notify(ctx, sync_type, str_c(state_str));
	return _ctx->exit_code == 0 ? 0 : -1;
}
int mail_storage_service_next(struct mail_storage_service_ctx *ctx,
			      struct mail_storage_service_user *user,
			      struct mail_user **mail_user_r)
{
	char *old_log_prefix = i_strdup(i_get_failure_prefix());
	int ret;

	mail_storage_service_set_log_prefix(ctx, user->user_set, user,
					    &user->input, NULL);
	i_set_failure_prefix("%s", old_log_prefix);
	ret = mail_storage_service_next_real(ctx, user, mail_user_r);
	if ((user->flags & MAIL_STORAGE_SERVICE_FLAG_NO_LOG_INIT) != 0)
		i_set_failure_prefix("%s", old_log_prefix);
	i_free(old_log_prefix);
	return ret;
}
Example #4
0
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);
}
int mail_storage_service_lookup(struct mail_storage_service_ctx *ctx,
				const struct mail_storage_service_input *input,
				struct mail_storage_service_user **user_r,
				const char **error_r)
{
	char *old_log_prefix = i_strdup(i_get_failure_prefix());
	bool update_log_prefix;
	int ret;

	if (io_loop_get_current_context(current_ioloop) == NULL) {
		/* no user yet. log prefix should be just "imap:" or something
		   equally unhelpful. we don't know the proper log format yet,
		   but initialize it to something better until we know it. */
		const char *session_id =
			input->session_id != NULL ? input->session_id :
			(input->session_id_prefix != NULL ?
			 input->session_id_prefix : NULL);
		i_set_failure_prefix("%s(%s%s,%s)",
			master_service_get_name(ctx->service), input->username,
			session_id == NULL ? "" : t_strdup_printf(",%s", session_id),
			input->remote_ip.family == 0 ? "" :
				t_strdup_printf(",%s", net_ip2addr(&input->remote_ip)));
		update_log_prefix = TRUE;
	} else {
		/* we might be here because we're doing a user lookup for a
		   shared user. the log prefix is likely already usable, so
		   just append our own without replacing the whole thing. */
		i_set_failure_prefix("%suser-lookup(%s)",
				     old_log_prefix, input->username);
		update_log_prefix = FALSE;
	}

	ret = mail_storage_service_lookup_real(ctx, input, update_log_prefix,
					       user_r, error_r);
	i_set_failure_prefix("%s", old_log_prefix);
	i_free(old_log_prefix);
	return ret;
}
static void
mail_storage_service_set_log_prefix(struct mail_storage_service_ctx *ctx,
				    const struct mail_user_settings *user_set,
				    struct mail_storage_service_user *user,
				    const struct mail_storage_service_input *input,
				    const struct mail_storage_service_privileges *priv)
{
	string_t *str;

	str = t_str_new(256);
	mail_storage_service_var_expand(ctx, str, user_set->mail_log_prefix,
					user, input, priv);
	i_set_failure_prefix("%s", str_c(str));
}
Example #7
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;
}
Example #8
0
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;
}
void mail_storage_service_io_deactivate(struct mail_storage_service_ctx *ctx)
{
	i_set_failure_prefix("%s", ctx->default_log_prefix);
}
void mail_storage_service_io_deactivate_user(struct mail_storage_service_user *user)
{
	i_set_failure_prefix("%s", user->service_ctx->default_log_prefix);
}
void mail_storage_service_io_activate_user(struct mail_storage_service_user *user)
{
	i_set_failure_prefix("%s", user->log_prefix);
}
Example #12
0
static void cmd_dsync_run_remote(struct mail_user *user)
{
	i_set_failure_prefix("dsync-local(%s): ", user->username);
	io_loop_run(current_ioloop);
}
Example #13
0
static int
cmd_dsync_run_local(struct dsync_cmd_context *ctx, struct mail_user *user,
		    struct dsync_brain *brain, struct dsync_ibc *ibc2,
		    bool *changes_during_sync_r)
{
	struct dsync_brain *brain2;
	struct mail_user *user2;
	struct setting_parser_context *set_parser;
	const char *set_line, *location;
	bool brain1_running, brain2_running, changed1, changed2;
	int ret;

	if (ctx->local_location_from_arg)
		location = ctx->ctx.args[0];
	else {
		i_assert(ctx->local_location != NULL);
		location = ctx->local_location;
	}

	i_set_failure_prefix("dsync(%s): ", user->username);

	/* update mail_location and create another user for the
	   second location. */
	set_parser = mail_storage_service_user_get_settings_parser(ctx->ctx.cur_service_user);
	set_line = t_strconcat("mail_location=", location, NULL);
	if (settings_parse_line(set_parser, set_line) < 0)
		i_unreached();
	ret = mail_storage_service_next(ctx->ctx.storage_service,
					ctx->ctx.cur_service_user, &user2);
	if (ret < 0) {
		ctx->ctx.exit_code = ret == -1 ? EX_TEMPFAIL : EX_CONFIG;
		return -1;
	}
	doveadm_user_init_dsync(user2);

	if (mail_namespaces_get_root_sep(user->namespaces) !=
	    mail_namespaces_get_root_sep(user2->namespaces)) {
		i_error("Mail locations must use the same "
			"virtual mailbox hierarchy separator "
			"(specify separator for the default namespace)");
		ctx->ctx.exit_code = EX_CONFIG;
		mail_user_unref(&user2);
		return -1;
	}
	if (paths_are_equal(user, user2, MAILBOX_LIST_PATH_TYPE_MAILBOX) &&
	    paths_are_equal(user, user2, MAILBOX_LIST_PATH_TYPE_INDEX)) {
		i_error("Both source and destination mail_location "
			"points to same directory: %s",
			mailbox_list_get_root_forced(user->namespaces->list,
						     MAILBOX_LIST_PATH_TYPE_MAILBOX));
		ctx->ctx.exit_code = EX_CONFIG;
		mail_user_unref(&user2);
		return -1;
	}

	brain2 = dsync_brain_slave_init(user2, ibc2, TRUE);
	mail_user_unref(&user2);

	brain1_running = brain2_running = TRUE;
	changed1 = changed2 = TRUE;
	while (brain1_running || brain2_running) {
		if (dsync_brain_has_failed(brain) ||
		    dsync_brain_has_failed(brain2))
			break;

		i_assert(changed1 || changed2);
		brain1_running = dsync_brain_run(brain, &changed1);
		brain2_running = dsync_brain_run(brain2, &changed2);
	}
	*changes_during_sync_r = dsync_brain_has_unexpected_changes(brain2);
	if (dsync_brain_deinit(&brain2) < 0) {
		ctx->ctx.exit_code = EX_TEMPFAIL;
		return -1;
	}
	return 0;
}
Example #14
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);
	}
}
Example #15
0
static int
client_handle_user_command(struct client *client, const char *cmd,
			   const char *const *args, const char **error_r)
{
	struct mail_storage_service_input input;
	struct imap_urlauth_worker_settings *set;
	struct mail_storage_service_user *user;
	struct imap_urlauth_config config;
	struct mail_user *mail_user;
	const char *error;
	unsigned int count;
	int ret;

	/* "USER\t"<username> */
	*error_r = NULL;

	/* check command syntax */
	if (strcmp(cmd, "USER") != 0) {
		*error_r = t_strconcat("Unknown or inappropriate command: ",
				       cmd, NULL);
		return -1;
	}

	if (args[0] == NULL || args[1] != NULL) {
		*error_r = "USER: Invalid number of parameters";
		return -1;
	}

	/* lookup user */
	memset(&input, 0, sizeof(input));
	input.module = "imap-urlauth-worker";
	input.service = "imap-urlauth-worker";
	input.username = args[0];

	if (client->debug)
		i_debug("Looking up user %s", input.username);

	ret = mail_storage_service_lookup_next(storage_service, &input,
					       &user, &mail_user, &error);
	if (ret < 0) {
		i_error("Failed to lookup user %s: %s", input.username, error);
		client_abort(client, "Session aborted: Failed to lookup user");
		return 0;
	} else if (ret == 0) {
		if (client->debug)
			i_debug("User %s doesn't exist", input.username);

		client_send_line(client, "NO");
		timeout_remove(&client->to_delay);
		return 1;
	}

	client->debug = mail_user->mail_debug =
		client->debug || mail_user->mail_debug;

	/* drop privileges */
	restrict_access_allow_coredumps(TRUE);

	set = mail_storage_service_user_get_set(user)[1];
	settings_var_expand(&imap_urlauth_worker_setting_parser_info, set,
			    mail_user->pool,
			    mail_user_var_expand_table(mail_user));

	if (set->verbose_proctitle) {
		verbose_proctitle = TRUE;
		imap_urlauth_worker_refresh_proctitle();
	}

	client->service_user = user;
	client->mail_user = mail_user;
	client->set = set;

	if (client->debug) {
		i_debug("Found user account `%s' on behalf of user `%s'",
			mail_user->username, client->access_user);
	}

	/* initialize urlauth context */
	if (*set->imap_urlauth_host == '\0') {
		i_error("imap_urlauth_host setting is not configured for user %s",
			mail_user->username);
		client_send_line(client, "NO");
		client_abort(client, "Session aborted: URLAUTH not configured");
		return 0;
	}

	memset(&config, 0, sizeof(config));
	config.url_host = set->imap_urlauth_host;
	config.url_port = set->imap_urlauth_port;
	config.access_user = client->access_user;
	config.access_anonymous = client->access_anonymous;
	config.access_applications =
		(const void *)array_get(&client->access_apps, &count);
		
	client->urlauth_ctx = imap_urlauth_init(client->mail_user, &config);
	if (client->debug) {
		i_debug("Providing access to user account `%s' on behalf of `%s'",
			mail_user->username, client->access_user);
	}

	i_set_failure_prefix("imap-urlauth[%s](%s->%s): ",
			     my_pid, client->access_user, mail_user->username);

	client_send_line(client, "OK");
	return 1;
}