static int
generate_dh_parameters(int bitsize, buffer_t *output, const char **error_r)
{
    DH *dh;
    unsigned char *p;
    int len, len2;

    dh = DH_generate_parameters(bitsize, DH_GENERATOR, NULL, NULL);
    if (dh == NULL) {
        *error_r = t_strdup_printf(
                       "DH_generate_parameters(bits=%d, gen=%d) failed: %s",
                       bitsize, DH_GENERATOR, openssl_iostream_error());
        return -1;
    }

    len = i2d_DHparams(dh, NULL);
    if (len < 0) {
        *error_r = t_strdup_printf("i2d_DHparams() failed: %s",
                                   openssl_iostream_error());
        DH_free(dh);
        return -1;
    }

    buffer_append(output, &bitsize, sizeof(bitsize));
    buffer_append(output, &len, sizeof(len));

    p = buffer_append_space_unsafe(output, len);
    len2 = i2d_DHparams(dh, &p);
    i_assert(len == len2);
    DH_free(dh);
    return 0;
}
static int
mail_transaction_log_file_read_more(struct mail_transaction_log_file *file)
{
	void *data;
	size_t size;
	uint32_t read_offset;
	ssize_t ret;

	read_offset = file->buffer_offset + file->buffer->used;

	do {
		data = buffer_append_space_unsafe(file->buffer, LOG_PREFETCH);
		ret = pread(file->fd, data, LOG_PREFETCH, read_offset);
		if (ret > 0)
			read_offset += ret;

		size = read_offset - file->buffer_offset;
		buffer_set_used_size(file->buffer, size);
	} while (ret > 0 || (ret < 0 && errno == EINTR));

	file->last_size = read_offset;

	if (ret < 0) {
		if (errno == ESTALE) {
			/* log file was deleted in NFS server, fail silently */
			return 0;
		}
		log_file_set_syscall_error(file, "pread()");
		return -1;
	}
	return 1;
}
Пример #3
0
static void test_buffer_set_used_size(void)
{
	buffer_t *buf;

	test_begin("buffer_set_used_size");
	buf = t_buffer_create(8);
	memset(buffer_append_space_unsafe(buf, 7), 'a', 7);
	buffer_set_used_size(buf, 4);
	test_assert(memcmp(buffer_get_space_unsafe(buf, 0, 7), "aaaa\0\0\0", 7) == 0);
	memset(buffer_get_space_unsafe(buf, 4, 7), 'b', 7);
	buffer_set_used_size(buf, 10);
	test_assert(memcmp(buffer_append_space_unsafe(buf, 1), "\0", 1) == 0);
	buffer_set_used_size(buf, 11);
	test_assert(memcmp(buffer_get_space_unsafe(buf, 0, 11), "aaaabbbbbb\0", 11) == 0);
	test_end();
}
Пример #4
0
void binary_to_hex_append(string_t *dest, const unsigned char *data,
			  size_t size)
{
	unsigned char *buf;

	buf = buffer_append_space_unsafe(dest, size * 2);
	binary_to_hex_case(buf, data, size, FALSE);
}
Пример #5
0
static int dump_record(int fd, buffer_t *buf)
{
	struct fts_expunge_log_record rec;
	off_t offset;
	void *data;
	const uint32_t *expunges, *uids;
	ssize_t ret;
	size_t data_size;
	unsigned int i, uids_count;

	offset = lseek(fd, 0, SEEK_CUR);

	ret = read(fd, &rec, sizeof(rec));
	if (ret == 0)
		return 0;

	if (ret != sizeof(rec))
		i_fatal("rec read() %d != %d", (int)ret, (int)sizeof(rec));

	if (rec.record_size < sizeof(rec) + sizeof(uint32_t) ||
	    rec.record_size > INT_MAX) {
		i_fatal("Invalid record_size=%u at offset %"PRIuUOFF_T,
			rec.record_size, offset);
	}
	data_size = rec.record_size - sizeof(rec);
	buffer_set_used_size(buf, 0);
	data = buffer_append_space_unsafe(buf, data_size);
	ret = read(fd, data, data_size);
	if (ret != (ssize_t)data_size)
		i_fatal("rec read() %d != %d", (int)ret, (int)data_size);

	printf("#%"PRIuUOFF_T":\n", offset);
	printf("  checksum  = %8x\n", rec.checksum);
	printf("  size .... = %u\n", rec.record_size);
	printf("  mailbox . = %s\n", guid_128_to_string(rec.guid));

	expunges = CONST_PTR_OFFSET(data, data_size - sizeof(uint32_t));
	printf("  expunges  = %u\n", *expunges);

	printf("  uids .... = ");

	uids = data;
	uids_count = (rec.record_size - sizeof(rec) - sizeof(uint32_t)) /
		sizeof(uint32_t);
	for (i = 0; i < uids_count; i += 2) {
		if (i != 0)
			printf(",");
		if (uids[i] == uids[i+1])
			printf("%u", uids[i]);
		else
			printf("%u-%u", uids[i], uids[i+1]);
	}
	printf("\n");
	return 1;
}
static void log_write_ext_hdr_init_data(struct mail_index *index, buffer_t *buf)
{
	const struct mail_index_registered_ext *rext;
	struct mail_transaction_header *hdr;
	struct mail_transaction_ext_intro *intro;
	struct mail_transaction_ext_hdr_update *ext_hdr;
	unsigned int hdr_offset;

	rext = array_idx(&index->extensions, index->ext_hdr_init_id);

	/* introduce the extension */
	hdr_offset = buf->used;
	hdr = buffer_append_space_unsafe(buf, sizeof(*hdr));
	hdr->type = MAIL_TRANSACTION_EXT_INTRO;

	intro = buffer_append_space_unsafe(buf, sizeof(*intro));
	intro->ext_id = (uint32_t)-1;
	intro->hdr_size = rext->hdr_size;
	intro->record_size = rext->record_size;
	intro->record_align = rext->record_align;
	intro->name_size = strlen(rext->name);
	buffer_append(buf, rext->name, intro->name_size);
	if (buf->used % 4 != 0)
		buffer_append_zero(buf, 4 - buf->used % 4);

	hdr = buffer_get_space_unsafe(buf, hdr_offset, sizeof(*hdr));
	hdr->size = mail_index_uint32_to_offset(buf->used - hdr_offset);

	/* add the extension header data */
	hdr_offset = buf->used;
	hdr = buffer_append_space_unsafe(buf, sizeof(*hdr));
	hdr->type = MAIL_TRANSACTION_EXT_HDR_UPDATE;

	ext_hdr = buffer_append_space_unsafe(buf, sizeof(*ext_hdr));
	ext_hdr->size = rext->hdr_size;
	buffer_append(buf, index->ext_hdr_init_data, rext->hdr_size);

	hdr = buffer_get_space_unsafe(buf, hdr_offset, sizeof(*hdr));
	hdr->size = mail_index_uint32_to_offset(buf->used - hdr_offset);
}
static ssize_t
mail_transaction_log_file_read_header(struct mail_transaction_log_file *file)
{
	void *dest;
	size_t pos, dest_size;
	ssize_t ret;

	i_assert(file->buffer == NULL && file->mmap_base == NULL);

	memset(&file->hdr, 0, sizeof(file->hdr));
	if (file->last_size < mmap_get_page_size() && file->last_size > 0) {
		/* just read the entire transaction log to memory.
		   note that if some of the data hasn't been fully committed
		   yet (hdr.size=0), the buffer must be truncated later */
		file->buffer = buffer_create_dynamic(default_pool, 4096);
		file->buffer_offset = 0;
		dest_size = file->last_size;
		dest = buffer_append_space_unsafe(file->buffer, dest_size);
	} else {
		/* read only the header */
		dest = &file->hdr;
		dest_size = sizeof(file->hdr);
	}

	/* it's not necessarily an error to read less than wanted header size,
	   since older versions of the log format used smaller headers. */
        pos = 0;
	do {
		ret = pread(file->fd, PTR_OFFSET(dest, pos),
			    dest_size - pos, pos);
		if (ret > 0)
			pos += ret;
	} while (ret > 0 && pos < dest_size);

	if (file->buffer != NULL) {
		buffer_set_used_size(file->buffer, pos);
		memcpy(&file->hdr, file->buffer->data,
		       I_MIN(pos, sizeof(file->hdr)));
	}

	return ret < 0 ? -1 : (ssize_t)pos;
}
Пример #8
0
static int ssl_refresh_parameters(struct master_service *service)
{
#define BUF_APPEND_SIZE 1024
	const char *path;
	buffer_t *buf;
	void *data;
	ssize_t ret;
	int fd;

	if (ioloop_time == 0 ||
	    service->ssl_params_last_refresh > ioloop_time - SSL_PARAMS_CHECK_INTERVAL)
		return 0;
	service->ssl_params_last_refresh = ioloop_time;

	path = t_strdup_printf("%s/"SSL_PARAMETERS_PATH, service->set->base_dir);
	fd = net_connect_unix(path);
	if (fd == -1) {
		i_error("connect(%s) failed: %m", path);
		return -1;
	}
	net_set_nonblock(fd, FALSE);

	buf = buffer_create_dynamic(default_pool, BUF_APPEND_SIZE*2);
	for (;;) {
		data = buffer_append_space_unsafe(buf, BUF_APPEND_SIZE);
		ret = read(fd, data, BUF_APPEND_SIZE);
		buffer_set_used_size(buf, buf->used - BUF_APPEND_SIZE +
				     (ret < 0 ? 0 : ret));
		if (ret <= 0)
			break;
	}
	if (ret < 0)
		i_error("read(%s) failed: %m", path);
	else if (ssl_iostream_context_import_params(service->ssl_ctx, buf) < 0) {
		i_error("Corrupted SSL parameters file in state_dir: "
			"ssl-parameters.dat - disabling SSL %u", (int)buf->used);
		ret = -1;
	}
	i_close_fd(&fd);
	buffer_free(&buf);
	return ret < 0 ? -1 : 0;
}
Пример #9
0
static int i_stream_seekable_write_failed(struct seekable_istream *sstream)
{
    struct istream_private *stream = &sstream->istream;
    void *data;

    i_assert(sstream->membuf == NULL);

    sstream->membuf =
        buffer_create_dynamic(default_pool, sstream->write_peak);
    data = buffer_append_space_unsafe(sstream->membuf, sstream->write_peak);

    if (pread_full(sstream->fd, data, sstream->write_peak, 0) < 0) {
        i_error("istream-seekable: read(%s) failed: %m", sstream->temp_path);
        buffer_free(&sstream->membuf);
        return -1;
    }
    i_stream_destroy(&sstream->fd_input);
    i_close_fd(&sstream->fd);

    stream->max_buffer_size = (size_t)-1;
    i_free_and_null(sstream->temp_path);
    return 0;
}
Пример #10
0
static void keywords_ext_register(struct mail_index_sync_map_ctx *ctx,
				  uint32_t ext_map_idx, uint32_t reset_id,
				  uint32_t hdr_size, uint32_t keywords_count)
{
	buffer_t ext_intro_buf;
	struct mail_transaction_ext_intro *u;
	unsigned char ext_intro_data[sizeof(*u) +
				     sizeof(MAIL_INDEX_EXT_KEYWORDS)-1];

	i_assert(keywords_count > 0);

	buffer_create_from_data(&ext_intro_buf, ext_intro_data,
				sizeof(ext_intro_data));

	u = buffer_append_space_unsafe(&ext_intro_buf, sizeof(*u));
	u->ext_id = ext_map_idx;
	u->reset_id = reset_id;
	u->hdr_size = hdr_size;
	u->record_size = (keywords_count + CHAR_BIT - 1) / CHAR_BIT;
	if ((u->record_size % 4) != 0) {
		/* since we aren't properly aligned anyway,
		   reserve one extra byte for future */
		u->record_size++;
	}
	u->record_align = 1;

	if (ext_map_idx == (uint32_t)-1) {
		u->name_size = strlen(MAIL_INDEX_EXT_KEYWORDS);
		buffer_append(&ext_intro_buf, MAIL_INDEX_EXT_KEYWORDS,
			      u->name_size);
	}

	ctx->internal_update = TRUE;
	if (mail_index_sync_ext_intro(ctx, u) < 0)
		i_panic("Keyword extension growing failed");
	ctx->internal_update = FALSE;
}
Пример #11
0
static void mbox_save_x_delivery_id(struct mbox_save_context *ctx)
{
	unsigned char md5_result[MD5_RESULTLEN];
	buffer_t *buf;
	string_t *str;
	void *randbuf;

	buf = buffer_create_dynamic(pool_datastack_create(), 256);
	buffer_append(buf, &ioloop_time, sizeof(ioloop_time));
	buffer_append(buf, &ioloop_timeval.tv_usec,
		      sizeof(ioloop_timeval.tv_usec));

	randbuf = buffer_append_space_unsafe(buf, MBOX_DELIVERY_ID_RAND_BYTES);
	random_fill_weak(randbuf, MBOX_DELIVERY_ID_RAND_BYTES);

	md5_get_digest(buf->data, buf->used, md5_result);

	str = t_str_new(128);
	str_append(str, "X-Delivery-ID: ");
	base64_encode(md5_result, sizeof(md5_result), str);
	str_append_c(str, '\n');

	ctx->x_delivery_id_header = i_strdup(str_c(str));
}
Пример #12
0
static void
keywords_header_add(struct mail_index_sync_map_ctx *ctx,
		    const char *keyword_name, unsigned int *keyword_idx_r)
{
	struct mail_index_map *map;
        const struct mail_index_ext *ext = NULL;
	struct mail_index_keyword_header *kw_hdr;
	struct mail_index_keyword_header_rec kw_rec;
	uint32_t ext_map_idx;
	buffer_t *buf = NULL;
	size_t keyword_len, rec_offset, name_offset, name_offset_root;
	unsigned int keywords_count;

	/* if we crash in the middle of writing the header, the
	   keywords are more or less corrupted. avoid that by
	   making sure the header is updated atomically. */
	map = mail_index_sync_get_atomic_map(ctx);

	if (!mail_index_map_lookup_ext(map, MAIL_INDEX_EXT_KEYWORDS,
				       &ext_map_idx))
		ext_map_idx = (uint32_t)-1;
	else {
		/* update existing header */
		ext = array_idx(&map->extensions, ext_map_idx);
		buf = keywords_get_header_buf(map, ext, 1, &keywords_count,
					      &rec_offset, &name_offset_root,
					      &name_offset);
	}

	if (buf == NULL) {
		/* create new / replace broken header */
		const unsigned int initial_keywords_count = 1;

		buf = buffer_create_dynamic(pool_datastack_create(), 512);
		kw_hdr = buffer_append_space_unsafe(buf, sizeof(*kw_hdr));
		kw_hdr->keywords_count = initial_keywords_count;

                keywords_count = kw_hdr->keywords_count;
		rec_offset = buf->used;
		name_offset_root = rec_offset +
			initial_keywords_count * sizeof(kw_rec);
		name_offset = 0;
	}

	/* add the keyword */
	memset(&kw_rec, 0, sizeof(kw_rec));
	kw_rec.name_offset = name_offset;

	keyword_len = strlen(keyword_name) + 1;
	buffer_write(buf, rec_offset, &kw_rec, sizeof(kw_rec));
	buffer_write(buf, name_offset_root, keyword_name, keyword_len);

	rec_offset += sizeof(kw_rec);
	kw_rec.name_offset += keyword_len;
	name_offset_root += keyword_len;

	if ((buf->used % 4) != 0)
		buffer_append_zero(buf, 4 - (buf->used % 4));

	if (ext == NULL || buf->used > ext->hdr_size ||
	    (uint32_t)ext->record_size * CHAR_BIT < keywords_count) {
		/* if we need to grow the buffer, add some padding */
		buffer_append_zero(buf, 128);
		keywords_ext_register(ctx, ext_map_idx,
				      ext == NULL ? 0 : ext->reset_id,
				      buf->used, keywords_count);

		/* map may have changed */
		map = ctx->view->map;

		if (!mail_index_map_lookup_ext(map, MAIL_INDEX_EXT_KEYWORDS,
					       &ext_map_idx))
			i_unreached();
		ext = array_idx(&map->extensions, ext_map_idx);

		i_assert(ext->hdr_size == buf->used);
	}

	buffer_copy(map->hdr_copy_buf, ext->hdr_offset, buf, 0, buf->used);
	map->hdr_base = map->hdr_copy_buf->data;
	i_assert(map->hdr_copy_buf->used == map->hdr.header_size);

	if (mail_index_map_parse_keywords(map) < 0)
		i_panic("Keyword update corrupted keywords header");

	*keyword_idx_r = keywords_count - 1;
	i_assert(*keyword_idx_r / CHAR_BIT < ext->record_size);
}
Пример #13
0
static bool client_exec_script(struct master_service_connection *conn)
{
	ARRAY_TYPE(const_string) envs;
	const char *const *args;
	string_t *input;
	void *buf;
	size_t prev_size, scanpos;
	bool header_complete = FALSE, noreply = FALSE;
	ssize_t ret;
	int status;
	pid_t pid;

	net_set_nonblock(conn->fd, FALSE);
	input = t_buffer_create(IO_BLOCK_SIZE);

	/* Input contains:

	   VERSION .. <lf>
	   [alarm=<secs> <lf>]
	   "noreply" | "-" (or anything really) <lf>

	   arg 1 <lf>
	   arg 2 <lf>
	   ...
	   <lf>
	   DATA

	   This is quite a horrible protocol. If alarm is specified, it MUST be
	   before "noreply". If "noreply" isn't given, something other string
	   (typically "-") must be given which is eaten away.
	*/		
	alarm(SCRIPT_READ_TIMEOUT_SECS);
	scanpos = 1;
	while (!header_complete) {
		const unsigned char *pos, *end;

		prev_size = input->used;
		buf = buffer_append_space_unsafe(input, IO_BLOCK_SIZE);

		/* peek in socket input buffer */
		ret = recv(conn->fd, buf, IO_BLOCK_SIZE, MSG_PEEK);
		if (ret <= 0) {
			buffer_set_used_size(input, prev_size);
			if (strchr(str_c(input), '\n') != NULL)
				script_verify_version(t_strcut(str_c(input), '\n'));

			if (ret < 0)
				i_fatal("recv(MSG_PEEK) failed: %m");

			i_fatal("recv(MSG_PEEK) failed: disconnected");
		}

		/* scan for final \n\n */
		pos = CONST_PTR_OFFSET(input->data, scanpos);
		end = CONST_PTR_OFFSET(input->data, prev_size + ret);
		for (; pos < end; pos++) {
			if (pos[-1] == '\n' && pos[0] == '\n') {
				header_complete = TRUE;
				pos++;
				break;
			}
		}
		scanpos = pos - (const unsigned char *)input->data;

		/* read data for real (up to and including \n\n) */
		ret = recv(conn->fd, buf, scanpos-prev_size, 0);
		if (prev_size+ret != scanpos) {
			if (ret < 0)
				i_fatal("recv() failed: %m");
			if (ret == 0)
				i_fatal("recv() failed: disconnected");
			i_fatal("recv() failed: size of definitive recv() differs from peek");
		}
		buffer_set_used_size(input, scanpos);
	}
	alarm(0);

	/* drop the last two LFs */
	buffer_set_used_size(input, scanpos-2);

	args = t_strsplit(str_c(input), "\n");
	script_verify_version(*args); args++;
	t_array_init(&envs, 16);
	if (*args != NULL) {
		const char *p;

		if (str_begins(*args, "alarm=")) {
			unsigned int seconds;
			if (str_to_uint(*args + 6, &seconds) < 0)
				i_fatal("invalid alarm option");
			alarm(seconds);
			args++;
		}
		while (str_begins(*args, "env_")) {
			const char *envname, *env;

			env = t_str_tabunescape(*args+4);
			p = strchr(env, '=');
			if (p == NULL)
				i_fatal("invalid environment variable");
			envname = t_strdup_until(*args+4, p);

			if (str_array_find(accepted_envs, envname))
				array_append(&envs, &env, 1);
			args++;
		}
		if (strcmp(*args, "noreply") == 0) {
			noreply = TRUE;
		}
		if (**args == '\0')
			i_fatal("empty options");
		args++;
	}
	array_append_zero(&envs);

	if (noreply) {
		/* no need to fork and check exit status */
		exec_child(conn, args, array_idx(&envs, 0));
		i_unreached();
	}

	if ((pid = fork()) == (pid_t)-1) {
		i_error("fork() failed: %m");
		return FALSE;
	}

	if (pid == 0) {
		/* child */
		exec_child(conn, args, array_idx(&envs, 0));
		i_unreached();
	}

	/* parent */

	/* check script exit status */
	if (waitpid(pid, &status, 0) < 0) {
		i_error("waitpid() failed: %m");
		return FALSE;
	} else if (WIFEXITED(status)) {
		ret = WEXITSTATUS(status);
		if (ret != 0) {
			i_error("Script terminated abnormally, exit status %d", (int)ret);
			return FALSE;
		}
	} else if (WIFSIGNALED(status)) {
		i_error("Script terminated abnormally, signal %d", WTERMSIG(status));
		return FALSE;
	} else if (WIFSTOPPED(status)) {
		i_fatal("Script stopped, signal %d", WSTOPSIG(status));
		return FALSE;
	} else {
		i_fatal("Script terminated abnormally, return status %d", status);
		return FALSE;
	}
	return TRUE;
}
Пример #14
0
static
int o_stream_encrypt_keydata_create_v2(struct encrypt_ostream *stream, const char *malg)
{
	const struct hash_method *hash = hash_method_lookup(malg);
	const char *error;
	size_t tagsize;
	const unsigned char *ptr;
	size_t kl;
	unsigned int val;

	buffer_t *keydata, *res;

	if (hash == NULL) {
		io_stream_set_error(&stream->ostream.iostream,
			"Encryption init error: Hash algorithm '%s' not supported", malg);
		return -1;
	}

	/* key data length for internal use */
	if ((stream->flags & IO_STREAM_ENC_INTEGRITY_HMAC) == IO_STREAM_ENC_INTEGRITY_HMAC) {
		tagsize = IOSTREAM_TAG_SIZE; 
	} else if ((stream->flags & IO_STREAM_ENC_INTEGRITY_AEAD) == IO_STREAM_ENC_INTEGRITY_AEAD) {
		tagsize = IOSTREAM_TAG_SIZE;
	} else {
		/* do not include MAC */
		tagsize = 0;
	}

	/* generate keydata length of random data for key/iv/mac */
	kl = dcrypt_ctx_sym_get_key_length(stream->ctx_sym) + dcrypt_ctx_sym_get_iv_length(stream->ctx_sym) + tagsize;
	keydata = buffer_create_dynamic(pool_datastack_create(), kl);
	random_fill(buffer_append_space_unsafe(keydata, kl), kl);
	buffer_set_used_size(keydata, kl);
	ptr = keydata->data;

	res = buffer_create_dynamic(default_pool, 256);

	/* store number of public key(s) */
	buffer_append(res, "\1", 1); /* one key for now */

	/* we can do multiple keys at this point, but do it only once now */
	if (o_stream_encrypt_key_for_pubkey_v2(stream, malg, ptr, kl, stream->pub, res) != 0) {
		buffer_free(&res);
		return -1;
	}

	/* create hash of the key data */
	unsigned char hctx[hash->context_size];
	unsigned char hres[hash->digest_size];
	hash->init(hctx);
	hash->loop(hctx, ptr, kl);
	hash->result(hctx, hres);

	for(int i = 1; i < 2049; i++) {
		uint32_t i_msb = htonl(i);

		hash->init(hctx);
		hash->loop(hctx, hres, sizeof(hres));
		hash->loop(hctx, &i_msb, sizeof(i_msb));
		hash->result(hctx, hres);
	}

	/* store key data hash */
	val = htonl(sizeof(hres));
	buffer_append(res, &val, 4);
	buffer_append(res, hres, sizeof(hres));

	/* pick up key data that goes into stream */
	stream->key_data_len = res->used;
	stream->key_data = buffer_free_without_data(&res);

	/* prime contexts */
	dcrypt_ctx_sym_set_key(stream->ctx_sym, ptr, dcrypt_ctx_sym_get_key_length(stream->ctx_sym));
	ptr += dcrypt_ctx_sym_get_key_length(stream->ctx_sym);
	dcrypt_ctx_sym_set_iv(stream->ctx_sym, ptr, dcrypt_ctx_sym_get_iv_length(stream->ctx_sym));
	ptr += dcrypt_ctx_sym_get_iv_length(stream->ctx_sym);

	if ((stream->flags & IO_STREAM_ENC_INTEGRITY_HMAC) == IO_STREAM_ENC_INTEGRITY_HMAC) {
		dcrypt_ctx_hmac_set_key(stream->ctx_mac, ptr, tagsize);
		dcrypt_ctx_hmac_init(stream->ctx_mac, &error);
	} else if ((stream->flags & IO_STREAM_ENC_INTEGRITY_AEAD) == IO_STREAM_ENC_INTEGRITY_AEAD) {
		dcrypt_ctx_sym_set_aad(stream->ctx_sym, ptr, tagsize);
	}

	/* clear out private key data */
	safe_memset(buffer_get_modifiable_data(keydata, 0), 0, keydata->used);

	if (!dcrypt_ctx_sym_init(stream->ctx_sym, &error)) {
		io_stream_set_error(&stream->ostream.iostream, "Encryption init error: %s", error);
		return -1;
	}
	return 0;
}
static void log_append_ext_intro(struct mail_index_export_context *ctx,
				 uint32_t ext_id, uint32_t reset_id)
{
	struct mail_index_transaction *t = ctx->trans;
	const struct mail_index_registered_ext *rext;
        struct mail_transaction_ext_intro *intro, *resizes;
	buffer_t *buf;
	uint32_t idx;
	unsigned int count;

	i_assert(ext_id != (uint32_t)-1);

	if (t->reset ||
	    !mail_index_map_get_ext_idx(t->view->index->map, ext_id, &idx)) {
		/* new extension */
		idx = (uint32_t)-1;
	}

	rext = array_idx(&t->view->index->extensions, ext_id);
	if (!array_is_created(&t->ext_resizes)) {
		resizes = NULL;
		count = 0;
	} else {
		resizes = array_get_modifiable(&t->ext_resizes, &count);
	}

	buf = buffer_create_dynamic(pool_datastack_create(), 128);
	if (ext_id < count && resizes[ext_id].name_size != 0) {
		/* we're resizing the extension. use the resize struct. */
		intro = &resizes[ext_id];

		i_assert(intro->ext_id == idx);
		intro->name_size = idx != (uint32_t)-1 ? 0 :
			strlen(rext->name);
		buffer_append(buf, intro, sizeof(*intro));
	} else {
		/* generate a new intro structure */
		intro = buffer_append_space_unsafe(buf, sizeof(*intro));
		intro->ext_id = idx;
		intro->hdr_size = rext->hdr_size;
		intro->record_size = rext->record_size;
		intro->record_align = rext->record_align;
		intro->flags = MAIL_TRANSACTION_EXT_INTRO_FLAG_NO_SHRINK;
		intro->name_size = idx != (uint32_t)-1 ? 0 :
			strlen(rext->name);
	}
	if (reset_id != 0) {
		/* we're going to reset this extension in this transaction */
		intro->reset_id = reset_id;
	} else if (idx != (uint32_t)-1) {
		/* use the existing reset_id */
		const struct mail_index_ext *map_ext =
			array_idx(&t->view->index->map->extensions, idx);
		intro->reset_id = map_ext->reset_id;
	} else {
		/* new extension, reset_id defaults to 0 */
	}
	buffer_append(buf, rext->name, intro->name_size);
	if ((buf->used % 4) != 0)
		buffer_append_zero(buf, 4 - (buf->used % 4));

	if (ctx->append_ctx->new_highest_modseq == 0 &&
	    strcmp(rext->name, MAIL_INDEX_MODSEQ_EXT_NAME) == 0) {
		/* modseq tracking started */
		ctx->append_ctx->new_highest_modseq = 1;
	}

	log_append_buffer(ctx, buf, MAIL_TRANSACTION_EXT_INTRO);
}