Beispiel #1
0
static struct istream *
mail_crypt_cache_open(struct mail_crypt_user *muser, struct mail *mail,
		      struct istream *input)
{
	struct mail_crypt_cache *cache = &muser->cache;
	struct istream *inputs[2];
	string_t *temp_prefix = t_str_new(128);

	mail_crypt_cache_close(muser);

	input->seekable = FALSE;
	inputs[0] = input;
	inputs[1] = NULL;
	mail_user_set_get_temp_prefix(temp_prefix, mail->box->storage->user->set);
	input = i_stream_create_seekable_path(inputs,
				i_stream_get_max_buffer_size(inputs[0]),
				str_c(temp_prefix));
	i_stream_unref(&inputs[0]);

	if (mail->uid > 0) {
		cache->to = timeout_add(MAIL_CRYPT_MAIL_CACHE_EXPIRE_MSECS,
				mail_crypt_cache_close, muser);
		cache->box = mail->box;
		cache->uid = mail->uid;
		cache->input = input;
		/* index-mail wants the stream to be destroyed at close, so create
		   a new stream instead of just increasing reference. */
		return i_stream_create_limit(cache->input, (uoff_t)-1);
	}

	return input;
}
static int seekable_fd_callback(const char **path_r, void *context)
{
	struct mail_user *user = context;
	string_t *path;
	int fd;

	path = t_str_new(128);
	mail_user_set_get_temp_prefix(path, user->set);
	fd = safe_mkstemp(path, 0600, (uid_t)-1, (gid_t)-1);
	if (fd == -1) {
		i_error("safe_mkstemp(%s) failed: %m", str_c(path));
		return -1;
	}

	/* we just want the fd, unlink it */
	if (unlink(str_c(path)) < 0) {
		/* shouldn't happen.. */
		i_error("unlink(%s) failed: %m", str_c(path));
		i_close_fd(&fd);
		return -1;
	}

	*path_r = str_c(path);
	return fd;
}
Beispiel #3
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;
}
Beispiel #4
0
static int
cmd_setmetadata_entry(struct imap_setmetadata_context *ctx,
                      const char *entry_name,
                      const struct imap_arg *entry_value)
{
    struct istream *inputs[2];
    struct mail_attribute_value value;
    string_t *path;
    int ret;

    switch (entry_value->type) {
    case IMAP_ARG_NIL:
    case IMAP_ARG_ATOM:
    case IMAP_ARG_STRING:
        /* we have the value already */
        if (ctx->failed)
            return 1;
        memset(&value, 0, sizeof(value));
        value.value = imap_arg_as_nstring(entry_value);
        ret = imap_metadata_set(ctx->trans, entry_name, &value);
        if (ret < 0) {
            /* delay reporting the failure so we'll finish
               reading the command input */
            ctx->storage_failure = TRUE;
            ctx->failed = TRUE;
        }
        return 1;
    case IMAP_ARG_LITERAL_SIZE:
        o_stream_nsend(ctx->cmd->client->output, "+ OK\r\n", 6);
        o_stream_nflush(ctx->cmd->client->output);
        o_stream_uncork(ctx->cmd->client->output);
        o_stream_cork(ctx->cmd->client->output);
    /* fall through */
    case IMAP_ARG_LITERAL_SIZE_NONSYNC:
        i_free(ctx->entry_name);
        ctx->entry_name = i_strdup(entry_name);
        ctx->entry_value_len = imap_arg_as_literal_size(entry_value);

        inputs[0] = i_stream_create_limit(ctx->cmd->client->input,
                                          ctx->entry_value_len);
        inputs[1] = NULL;

        path = t_str_new(128);
        mail_user_set_get_temp_prefix(path, ctx->cmd->client->user->set);
        ctx->input = i_stream_create_seekable_path(inputs,
                     METADATA_MAX_INMEM_SIZE, str_c(path));
        i_stream_set_name(ctx->input, i_stream_get_name(inputs[0]));
        i_stream_unref(&inputs[0]);
        return cmd_setmetadata_entry_read_stream(ctx);
    case IMAP_ARG_LITERAL:
    case IMAP_ARG_LIST:
    case IMAP_ARG_EOL:
        break;
    }
    i_unreached();
}
Beispiel #5
0
static int index_attachment_open_temp_fd(void *context)
{
	struct mail_save_context *ctx = context;
	struct mail_storage *storage = ctx->transaction->box->storage;
	string_t *temp_path;
	int fd;

	temp_path = t_str_new(256);
	mail_user_set_get_temp_prefix(temp_path, storage->user->set);
	fd = safe_mkstemp_hostpid(temp_path, 0600, (uid_t)-1, (gid_t)-1);
	if (fd == -1) {
		mail_storage_set_critical(storage,
			"safe_mkstemp(%s) failed: %m", str_c(temp_path));
		return -1;
	}
	if (unlink(str_c(temp_path)) < 0) {
		mail_storage_set_critical(storage,
			"unlink(%s) failed: %m", str_c(temp_path));
		i_close_fd(&fd);
		return -1;
	}
	return fd;
}
Beispiel #6
0
static struct istream *
zlib_mail_cache_open(struct zlib_user *zuser, struct mail *mail,
		     struct istream *input)
{
	struct zlib_mail_cache *cache = &zuser->cache;
	struct istream *inputs[2];
	string_t *temp_prefix = t_str_new(128);

	zlib_mail_cache_close(zuser);

	/* zlib istream is seekable, but very slow. create a seekable istream
	   which we can use to quickly seek around in the stream that's been
	   read so far. usually the partial IMAP FETCHes continue from where
	   the previous left off, so this isn't strictly necessary, but with
	   the way lib-imap-storage's CRLF-cache works it has to seek backwards
	   somewhat, which causes a zlib stream reset. And the CRLF-cache isn't
	   easy to fix.. */
	input->seekable = FALSE;
	inputs[0] = input;
	inputs[1] = NULL;
	mail_user_set_get_temp_prefix(temp_prefix, mail->box->storage->user->set);
	input = i_stream_create_seekable_path(inputs,
				i_stream_get_max_buffer_size(inputs[0]),
				str_c(temp_prefix));
	i_stream_unref(&inputs[0]);

	cache->to = timeout_add(ZLIB_MAIL_CACHE_EXPIRE_MSECS,
				zlib_mail_cache_close, zuser);
	cache->box = mail->box;
	cache->uid = mail->uid;
	cache->input = input;

	/* index-mail wants the stream to be destroyed at close, so create
	   a new stream instead of just increasing reference. */
	return i_stream_create_limit(cache->input, (uoff_t)-1);
}
Beispiel #7
0
static int
cmd_dsync_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, *ibc2 = NULL;
	struct dsync_brain *brain;
	struct dsync_brain_settings set;
	enum dsync_brain_flags brain_flags;
	bool remote_errors_logged = FALSE;
	bool changes_during_sync = FALSE;
	int status = 0, ret = 0;

	memset(&set, 0, sizeof(set));
	set.sync_box = ctx->mailbox;
	memcpy(set.sync_box_guid, ctx->mailbox_guid, sizeof(set.sync_box_guid));
	set.lock_timeout_secs = ctx->lock_timeout;
	set.state = ctx->state_input;
	if (array_count(&ctx->exclude_mailboxes) > 0) {
		/* array is NULL-terminated in init() */
		set.exclude_mailboxes = array_idx(&ctx->exclude_mailboxes, 0);
	}
	doveadm_user_init_dsync(user);

	if (ctx->namespace_prefix != NULL) {
		set.sync_ns = mail_namespace_find(user->namespaces,
						  ctx->namespace_prefix);
	}

	if (ctx->run_type == DSYNC_RUN_TYPE_LOCAL)
		dsync_ibc_init_pipe(&ibc, &ibc2);
	else {
		string_t *temp_prefix = t_str_new(64);
		mail_user_set_get_temp_prefix(temp_prefix, user->set);
		ibc = cmd_dsync_icb_stream_init(ctx, ctx->remote_name,
						str_c(temp_prefix));
		if (ctx->fd_err != -1) {
			ctx->io_err = io_add(ctx->fd_err, IO_READ,
					     remote_error_input, ctx);
		}
	}

	brain_flags = DSYNC_BRAIN_FLAG_SEND_MAIL_REQUESTS;
	if (ctx->sync_visible_namespaces)
		brain_flags |= DSYNC_BRAIN_FLAG_SYNC_VISIBLE_NAMESPACES;
	if (ctx->purge_remote)
		brain_flags |= DSYNC_BRAIN_FLAG_PURGE_REMOTE;

	if (ctx->reverse_backup)
		brain_flags |= DSYNC_BRAIN_FLAG_BACKUP_RECV;
	else if (ctx->backup)
		brain_flags |= DSYNC_BRAIN_FLAG_BACKUP_SEND;

	if (ctx->no_mail_sync)
		brain_flags |= DSYNC_BRAIN_FLAG_NO_MAIL_SYNC;
	if (ctx->oneway)
		brain_flags |= DSYNC_BRAIN_FLAG_NO_BACKUP_OVERWRITE;
	if (doveadm_debug)
		brain_flags |= DSYNC_BRAIN_FLAG_DEBUG;

	brain = dsync_brain_master_init(user, ibc, ctx->sync_type,
					brain_flags, &set);

	if (ctx->run_type == DSYNC_RUN_TYPE_LOCAL) {
		if (cmd_dsync_run_local(ctx, user, brain, ibc2,
					&changes_during_sync) < 0)
			ret = -1;
	} else {
		cmd_dsync_run_remote(user);
	}

	if (ctx->state_input != NULL) {
		string_t *state_str = t_str_new(128);
		dsync_brain_get_state(brain, state_str);
		doveadm_print(str_c(state_str));
	}

	if (dsync_brain_has_unexpected_changes(brain) || changes_during_sync) {
		/* don't log a warning when running via doveadm server
		   (e.g. called by replicator) */
		if (ctx->ctx.conn == NULL) {
			i_warning("Mailbox changes caused a desync. "
				  "You may want to run dsync again.");
		}
		ctx->ctx.exit_code = 2;
	}
	if (dsync_brain_deinit(&brain) < 0) {
		ctx->ctx.exit_code = EX_TEMPFAIL;
		ret = -1;
	}
	dsync_ibc_deinit(&ibc);
	if (ibc2 != NULL)
		dsync_ibc_deinit(&ibc2);
	if (ctx->ssl_iostream != NULL)
		ssl_iostream_destroy(&ctx->ssl_iostream);
	if (ctx->ssl_ctx != NULL)
		ssl_iostream_context_deinit(&ctx->ssl_ctx);
	if (ctx->input != NULL)
		i_stream_unref(&ctx->input);
	if (ctx->output != NULL)
		o_stream_unref(&ctx->output);
	if (ctx->fd_in != -1) {
		if (ctx->fd_out != ctx->fd_in)
			i_close_fd(&ctx->fd_out);
		i_close_fd(&ctx->fd_in);
	}
	if (ctx->run_type == DSYNC_RUN_TYPE_CMD)
		cmd_dsync_wait_remote(ctx, &status);

	/* print any final errors after the process has died. not closing
	   stdin/stdout before wait() may cause the process to hang, but stderr
	   shouldn't (at least with ssh) and we need stderr to be open to be
	   able to print the final errors */
	if (ctx->err_stream != NULL) {
		remote_error_input(ctx);
		remote_errors_logged = ctx->err_stream->v_offset > 0;
		i_stream_destroy(&ctx->err_stream);
	}
	if (ctx->run_type == DSYNC_RUN_TYPE_CMD)
		cmd_dsync_log_remote_status(status, remote_errors_logged);
	if (ctx->io_err != NULL)
		io_remove(&ctx->io_err);
	if (ctx->fd_err != -1)
		i_close_fd(&ctx->fd_err);

	return ret;
}