Example #1
0
static void
login_client_connected(const struct master_login_client *client,
		       const char *username, const char *const *extra_fields)
{
	struct mail_storage_service_input input;
	const char *error;
	buffer_t input_buf;

	memset(&input, 0, sizeof(input));
	input.module = input.service = "pop3";
	input.local_ip = client->auth_req.local_ip;
	input.remote_ip = client->auth_req.remote_ip;
	input.username = username;
	input.userdb_fields = extra_fields;
	input.session_id = client->session_id;

	buffer_create_from_const_data(&input_buf, client->data,
				      client->auth_req.data_size);
	if (client_create_from_input(&input, client->fd, client->fd,
				     &input_buf, &error) < 0) {
		int fd = client->fd;

		i_error("%s", error);
		i_close_fd(&fd);
		master_service_client_connection_destroyed(master_service);
	}
}
static int
mail_transaction_log_file_mmap(struct mail_transaction_log_file *file)
{
	if (file->buffer != NULL) {
		/* in case we just switched to mmaping */
		buffer_free(&file->buffer);
	}
	file->mmap_size = file->last_size;
	file->mmap_base = mmap(NULL, file->mmap_size, PROT_READ, MAP_SHARED,
			       file->fd, 0);
	if (file->mmap_base == MAP_FAILED) {
		file->mmap_base = NULL;
		file->mmap_size = 0;
		log_file_set_syscall_error(file, "mmap()");
		return -1;
	}

	if (file->mmap_size > mmap_get_page_size()) {
		if (madvise(file->mmap_base, file->mmap_size,
			    MADV_SEQUENTIAL) < 0)
			log_file_set_syscall_error(file, "madvise()");
	}

	buffer_create_from_const_data(&file->mmap_buffer,
				      file->mmap_base, file->mmap_size);
	file->buffer = &file->mmap_buffer;
	file->buffer_offset = 0;
	return 0;
}
Example #3
0
static void
login_client_connected(const struct master_login_client *client,
		       const char *username, const char *const *extra_fields)
{
#define MSG_BYE_INTERNAL_ERROR "* BYE "MAIL_ERRSTR_CRITICAL_MSG"\r\n"
	struct mail_storage_service_input input;
	const char *error;
	buffer_t input_buf;

	memset(&input, 0, sizeof(input));
	input.module = input.service = "imap";
	input.local_ip = client->auth_req.local_ip;
	input.remote_ip = client->auth_req.remote_ip;
	input.username = username;
	input.userdb_fields = extra_fields;
	input.session_id = client->session_id;

	buffer_create_from_const_data(&input_buf, client->data,
				      client->auth_req.data_size);
	if (client_create_from_input(&input, client, client->fd, client->fd,
				     &input_buf, &error) < 0) {
		int fd = client->fd;

		if (write(fd, MSG_BYE_INTERNAL_ERROR,
			  strlen(MSG_BYE_INTERNAL_ERROR)) < 0) {
			if (errno != EAGAIN && errno != EPIPE)
				i_error("write(client) failed: %m");
		}
		i_error("%s", error);
		i_close_fd(&fd);
		master_service_client_connection_destroyed(master_service);
	}
}
Example #4
0
static struct mail_save_context *
maildir_save_transaction_init(struct mailbox_transaction_context *t)
{
	struct maildir_mailbox *mbox = (struct maildir_mailbox *)t->box;
	struct maildir_save_context *ctx;
	const char *path;
	pool_t pool;

	pool = pool_alloconly_create("maildir_save_context", 4096);
	ctx = p_new(pool, struct maildir_save_context, 1);
	ctx->ctx.transaction = t;
	ctx->pool = pool;
	ctx->mbox = mbox;
	ctx->trans = t->itrans;
	ctx->files_tail = &ctx->files;
	ctx->fd = -1;

	path = mailbox_get_path(&mbox->box);
	ctx->tmpdir = p_strconcat(pool, path, "/tmp", NULL);
	ctx->newdir = p_strconcat(pool, path, "/new", NULL);
	ctx->curdir = p_strconcat(pool, path, "/cur", NULL);

	buffer_create_from_const_data(&ctx->keywords_buffer, "", 0);
	array_create_from_buffer(&ctx->keywords_array, &ctx->keywords_buffer,
				 sizeof(unsigned int));
	ctx->last_save_finished = TRUE;
	return &ctx->ctx;
}
Example #5
0
string_t *str_new_const(pool_t pool, const char *str, size_t len)
{
	string_t *ret;

	i_assert(str[len] == '\0');

	ret = p_new(pool, buffer_t, 1);
	buffer_create_from_const_data(ret, str, len + 1);
	str_truncate(ret, len);
	return ret;
}
Example #6
0
static bool
maildir_get_dest_filename(struct maildir_save_context *ctx,
			  struct maildir_filename *mf,
			  const char **fname_r)
{
	const char *basename = mf->dest_basename;

	if (mf->size != (uoff_t)-1 && !mf->preserve_filename) {
		basename = t_strdup_printf("%s,%c=%"PRIuUOFF_T, basename,
					   MAILDIR_EXTRA_FILE_SIZE, mf->size);
	}

	if (mf->vsize != (uoff_t)-1 && !mf->preserve_filename) {
		basename = t_strdup_printf("%s,%c=%"PRIuUOFF_T, basename,
					   MAILDIR_EXTRA_VIRTUAL_SIZE,
					   mf->vsize);
	}

	if (mf->keywords_count == 0) {
		if ((mf->flags & MAIL_FLAGS_MASK) == MAIL_RECENT) {
			*fname_r = basename;
			return TRUE;
		}

		*fname_r = maildir_filename_flags_set(basename,
					mf->flags & MAIL_FLAGS_MASK);
		return FALSE;
	}

	i_assert(ctx->keywords_sync_ctx != NULL || mf->keywords_count == 0);
	buffer_create_from_const_data(&ctx->keywords_buffer, mf + 1,
				      mf->keywords_count * sizeof(unsigned int));
	*fname_r = maildir_filename_flags_kw_set(ctx->keywords_sync_ctx,
						 basename,
						 mf->flags & MAIL_FLAGS_MASK,
						 &ctx->keywords_array);
	return FALSE;
}
Example #7
0
static
ssize_t i_stream_decrypt_read_header_v1(struct decrypt_istream *stream,
	const unsigned char *data, size_t mlen)
{
	const char *error = NULL;
	size_t keydata_len = 0;
	uint16_t len;
	int ec, i = 0;

	const unsigned char *digest_pos = NULL, *key_digest_pos = NULL, *key_ct_pos = NULL;

	size_t pos = sizeof(IOSTREAM_CRYPT_MAGIC);
	size_t digest_len = 0;
	size_t key_ct_len = 0;
	size_t key_digest_size = 0;

	buffer_t ephemeral_key;
	buffer_t *secret = buffer_create_dynamic(pool_datastack_create(), 256);
	buffer_t *key = buffer_create_dynamic(pool_datastack_create(), 256);

	if (mlen < 2)
		return 0;
	keydata_len = (data[0] << 8) | data[1];
	if (mlen-2 < keydata_len) {
		/* try to read more */
		return 0;
	}

	data+=2;
	mlen-=2;

	while (i < 4 && mlen > 2) {
		memcpy(&len, data, 2);
		len = ntohs(len);
		data += 2;
		mlen -= 2;
		pos += 2;
		if (len == 0 || len > mlen)
			break;

		switch(i++) {
		case 0:
			buffer_create_from_const_data(&ephemeral_key, data, len);
			break;
		case 1:
			/* public key id */
			digest_pos = data;
			digest_len = len;
			break;
		case 2:
			/* encryption key digest */
			key_digest_pos = data;
			key_digest_size = len;
			break;
		case 3:
			/* encrypted key data */
			key_ct_pos = data;
			key_ct_len = len;
			break;
		}
		pos += len;
		data += len;
		mlen -= len;
	}

	if (i < 4) {
		io_stream_set_error(&stream->istream.iostream, "Invalid or corrupted header");
		stream->istream.istream.stream_errno = EINVAL;
		return -1;
	}

	/* we don't have a private key */
	if (stream->priv_key == NULL) {
		/* see if we can get one */
		if (stream->key_callback != NULL) {
			const char *key_id = binary_to_hex(digest_pos, digest_len);
			int ret = stream->key_callback(key_id, &(stream->priv_key), &error, stream->key_context);
			if (ret < 0) {
				io_stream_set_error(&stream->istream.iostream, "Private key not available: %s", error);
				return -1;
			}
			if (ret == 0) {
				io_stream_set_error(&stream->istream.iostream, "Private key not available");
				return -1;
			}
			dcrypt_key_ref_private(stream->priv_key);
		} else {
			io_stream_set_error(&stream->istream.iostream, "Private key not available");
			return -1;
		}
	}

	buffer_t *check = buffer_create_dynamic(pool_datastack_create(), 32);

	if (!dcrypt_key_id_private_old(stream->priv_key, check, &error)) {
		io_stream_set_error(&stream->istream.iostream, "Cannot get public key hash: %s", error);
		return -1;
	} else {
		if (memcmp(digest_pos, check->data, I_MIN(digest_len,check->used)) != 0) {
			io_stream_set_error(&stream->istream.iostream, "Private key not available");
			return -1;
		}
	}

	/* derive shared secret */
	if (!dcrypt_ecdh_derive_secret_local(stream->priv_key, &ephemeral_key, secret, &error)) {
		io_stream_set_error(&stream->istream.iostream, "Cannot perform ECDH: %s", error);
		return -1;
	}

	/* run it thru SHA256 once */
	const struct hash_method *hash = &hash_method_sha256;
	unsigned char hctx[hash->context_size];
	unsigned char hres[hash->digest_size];
	hash->init(hctx);
	hash->loop(hctx, secret->data, secret->used);
	hash->result(hctx, hres);
	safe_memset(buffer_get_modifiable_data(secret, 0), 0, secret->used);

	/* NB! The old code was broken and used this kind of IV - it is not correct, but
	   we need to stay compatible with old data */

	/* use it to decrypt the actual encryption key */
	struct dcrypt_context_symmetric *dctx;
	if (!dcrypt_ctx_sym_create("aes-256-ctr", DCRYPT_MODE_DECRYPT, &dctx, &error)) {
		io_stream_set_error(&stream->istream.iostream, "Key decryption error: %s", error);
		return -1;
	}

	ec = 0;
	dcrypt_ctx_sym_set_iv(dctx, (const unsigned char*)"\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0", 16);
	dcrypt_ctx_sym_set_key(dctx, hres, hash->digest_size);
	if (!dcrypt_ctx_sym_init(dctx, &error) ||
	    !dcrypt_ctx_sym_update(dctx, key_ct_pos, key_ct_len, key, &error) ||
	    !dcrypt_ctx_sym_final(dctx, key, &error)) {
		io_stream_set_error(&stream->istream.iostream, "Key decryption error: %s", error);
		ec = -1;
	}
	dcrypt_ctx_sym_destroy(&dctx);

	if (ec != 0) {
		io_stream_set_error(&stream->istream.iostream, "Key decryption error: %s", error);
		return -1;
	}

	/* see if we got the correct key */
	hash->init(hctx);
	hash->loop(hctx, key->data, key->used);
	hash->result(hctx, hres);

	if (key_digest_size != sizeof(hres)) {
		io_stream_set_error(&stream->istream.iostream, "Key decryption error: invalid digest length");
		return -1;
	}
	if (memcmp(hres, key_digest_pos, sizeof(hres)) != 0) {
		io_stream_set_error(&stream->istream.iostream, "Key decryption error: decrypted key is invalid");
		return -1;
	}

	/* prime context with key */
	if (!dcrypt_ctx_sym_create("aes-256-ctr", DCRYPT_MODE_DECRYPT, &(stream->ctx_sym), &error)) {
		io_stream_set_error(&stream->istream.iostream, "Decryption context create error: %s", error);
		return -1;
	}

	/* Again, old code used this IV, so we have to use it too */
	dcrypt_ctx_sym_set_iv(stream->ctx_sym, (const unsigned char*)"\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0", 16);
	dcrypt_ctx_sym_set_key(stream->ctx_sym, key->data, key->used);

	safe_memset(buffer_get_modifiable_data(key, 0), 0, key->used);

	if (!dcrypt_ctx_sym_init(stream->ctx_sym, &error)) {
		io_stream_set_error(&stream->istream.iostream, "Decryption init error: %s", error);
		return -1;
	}

	stream->use_mac = FALSE;
	stream->initialized = TRUE;
	/* now we are ready to decrypt stream */

	return sizeof(IOSTREAM_CRYPT_MAGIC) + 1 + 2 + keydata_len;
}
Example #8
0
static
ssize_t i_stream_decrypt_key(struct decrypt_istream *stream, const char *malg, unsigned int rounds,
	const unsigned char *data, const unsigned char *end, buffer_t *key, size_t key_len)
{
	const char *error;
	enum dcrypt_key_type ktype;
	int keys;
	bool have_key = FALSE;
	unsigned char dgst[32];
	uint32_t val;
	buffer_t buf;

	if (data == end)
		return 0;

	keys = *data++;

	/* if we have a key, prefab the digest */
	if (stream->key_callback == NULL) {
		if (stream->priv_key == NULL) {	
			io_stream_set_error(&stream->istream.iostream, "Decryption error: no private key available");
			return -1;
		}
		buffer_create_from_data(&buf, dgst, sizeof(dgst));
		dcrypt_key_id_private(stream->priv_key, "sha256", &buf, NULL);
	}

	/* for each key */
	for(;keys>0;keys--) {
		if ((size_t)(end-data) < 1 + (ssize_t)sizeof(dgst))
			return 0;
		ktype = *data++;

		if (stream->key_callback != NULL) {
			const char *hexdgst = binary_to_hex(data, sizeof(dgst)); /* digest length */
			/* hope you going to give us right key.. */
			int ret = stream->key_callback(hexdgst, &(stream->priv_key), &error, stream->key_context);
			if (ret < 0) {
				io_stream_set_error(&stream->istream.iostream, "Private key not available: %s", error);
				return -1;
			}
			if (ret > 0) {
				dcrypt_key_ref_private(stream->priv_key);
				have_key = TRUE;
				break;
			}
		} else {
			/* see if key matches to the one we have */
			if (memcmp(dgst, data, sizeof(dgst)) == 0) {
			      	have_key = TRUE;
				break;
			}
		}
		data += sizeof(dgst);

		/* wasn't correct key, skip over some data */
		if (!get_msb32(&data, end, &val) ||
		    !get_msb32(&data, end, &val))
			return 0;
	}

	/* didn't find matching key */
	if (!have_key) {
		io_stream_set_error(&stream->istream.iostream, "Decryption error: no private key available");
		return -1;
	}

	data += sizeof(dgst);

	const unsigned char *ephemeral_key;
	uint32_t ep_key_len;
	const unsigned char *encrypted_key;
	uint32_t eklen;
	const unsigned char *ekhash;
	uint32_t ekhash_len;

	/* read ephemeral key (can be missing for RSA) */
	if (!get_msb32(&data, end, &ep_key_len) || (size_t)(end-data) < ep_key_len)
		return 0;
	ephemeral_key = data;
	data += ep_key_len;

	/* read encrypted key */
	if (!get_msb32(&data, end, &eklen) || (size_t)(end-data) < eklen)
		return 0;
	encrypted_key = data;
	data += eklen;

	/* read key data hash */
	if (!get_msb32(&data, end, &ekhash_len) || (size_t)(end-data) < ekhash_len)
		return 0;
	ekhash = data;
	data += ekhash_len;

	/* decrypt the seed */
	if (ktype == DCRYPT_KEY_RSA) {
		if (!dcrypt_rsa_decrypt(stream->priv_key, encrypted_key, eklen, key, &error)) {
			io_stream_set_error(&stream->istream.iostream, "key decryption error: %s", error);
			return -1;
		}
	} else if (ktype == DCRYPT_KEY_EC) {
		/* perform ECDHE */
		buffer_t *temp_key = buffer_create_dynamic(pool_datastack_create(), 256);
		buffer_t *secret = buffer_create_dynamic(pool_datastack_create(), 256);
		buffer_t peer_key;
		buffer_create_from_const_data(&peer_key, ephemeral_key, ep_key_len);
		if (!dcrypt_ecdh_derive_secret_local(stream->priv_key, &peer_key, secret, &error)) {
			io_stream_set_error(&stream->istream.iostream, "Key decryption error: corrupted header");
			return -1;
		}

		/* use shared secret and peer key to generate decryption key, AES-256-CBC has 32 byte key and 16 byte IV */
		if (!dcrypt_pbkdf2(secret->data, secret->used, peer_key.data, peer_key.used,
		    malg, rounds, temp_key, 32+16, &error)) {
			safe_memset(buffer_get_modifiable_data(secret, 0), 0, secret->used);
			io_stream_set_error(&stream->istream.iostream, "Key decryption error: %s", error);
			return -1;
		}

		safe_memset(buffer_get_modifiable_data(secret, 0), 0, secret->used);
		if (temp_key->used != 32+16) {
			safe_memset(buffer_get_modifiable_data(temp_key, 0), 0, temp_key->used);
			io_stream_set_error(&stream->istream.iostream, "Cannot perform key decryption: invalid temporary key");
			return -1;
		}
		struct dcrypt_context_symmetric *dctx;
		if (!dcrypt_ctx_sym_create("AES-256-CBC", DCRYPT_MODE_DECRYPT, &dctx, &error)) {
			safe_memset(buffer_get_modifiable_data(temp_key, 0), 0, temp_key->used);
			io_stream_set_error(&stream->istream.iostream, "Key decryption error: %s", error);
			return -1;
		}
		const unsigned char *ptr = temp_key->data;

		/* we use ephemeral_key for IV */
		dcrypt_ctx_sym_set_key(dctx, ptr, 32);
		dcrypt_ctx_sym_set_iv(dctx, ptr+32, 16);
		safe_memset(buffer_get_modifiable_data(temp_key, 0), 0, temp_key->used);

		int ec = 0;
		if (!dcrypt_ctx_sym_init(dctx, &error) ||
		    !dcrypt_ctx_sym_update(dctx, encrypted_key, eklen, key, &error) ||
		    !dcrypt_ctx_sym_final(dctx, key, &error)) {
			io_stream_set_error(&stream->istream.iostream, "Cannot perform key decryption: %s", error);
			ec = -1;
		}

		if (key->used != key_len) {
			io_stream_set_error(&stream->istream.iostream, "Cannot perform key decryption: invalid key length");
			ec = -1;
		}

		dcrypt_ctx_sym_destroy(&dctx);
		if (ec != 0) return ec;
	} else {
		io_stream_set_error(&stream->istream.iostream, "Decryption error: unsupported key type 0x%02x", ktype);
		return -1;
	}

	/* make sure we were able to decrypt the encrypted key correctly */
	const struct hash_method *hash = hash_method_lookup(t_str_lcase(malg));
	if (hash == NULL) {
		safe_memset(buffer_get_modifiable_data(key, 0), 0, key->used);
		io_stream_set_error(&stream->istream.iostream, "Decryption error: unsupported hash algorithm: %s", malg);
		return -1;
	}
	unsigned char hctx[hash->context_size];
	unsigned char hres[hash->digest_size];
	hash->init(hctx);
	hash->loop(hctx, key->data, key->used);
	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);
	}

	/* do the comparison */
	if (memcmp(ekhash, hres, I_MIN(ekhash_len, sizeof(hres))) != 0) {
		safe_memset(buffer_get_modifiable_data(key, 0), 0, key->used);
		io_stream_set_error(&stream->istream.iostream, "Decryption error: corrupted header ekhash");
		return -1;
	}
	return 1;
}