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; }
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); } }
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; }
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; }
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; }
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; }
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; }