/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "MetadataCrypt.h"
#include "KeyBuffer.h"

#include <algorithm>
#include <string>
#include <thread>
#include <vector>

#include <fcntl.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/types.h>

#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android-base/unique_fd.h>
#include <cutils/fs.h>
#include <fs_mgr.h>
#include <libdm/dm.h>

#include "Checkpoint.h"
#include "EncryptInplace.h"
#include "KeyStorage.h"
#include "KeyUtil.h"
#include "Keymaster.h"
#include "Utils.h"
#include "VoldUtil.h"

#define TABLE_LOAD_RETRIES 10

using android::fs_mgr::FstabEntry;
using android::fs_mgr::GetEntryForMountPoint;
using android::vold::KeyBuffer;
using namespace android::dm;

static const std::string kDmNameUserdata = "userdata";

static const char* kFn_keymaster_key_blob = "keymaster_key_blob";
static const char* kFn_keymaster_key_blob_upgraded = "keymaster_key_blob_upgraded";

static bool mount_via_fs_mgr(const char* mount_point, const char* blk_device) {
    // We're about to mount data not verified by verified boot.  Tell Keymaster that early boot has
    // ended.
    //
    // TODO(paulcrowley): Make a Keymaster singleton or something, so we don't have to repeatedly
    // open and initialize the service.
    ::android::vold::Keymaster keymaster;
    keymaster.earlyBootEnded();

    // fs_mgr_do_mount runs fsck. Use setexeccon to run trusted
    // partitions in the fsck domain.
    if (setexeccon(android::vold::sFsckContext)) {
        PLOG(ERROR) << "Failed to setexeccon";
        return false;
    }
    auto mount_rc = fs_mgr_do_mount(&fstab_default, const_cast<char*>(mount_point),
                                    const_cast<char*>(blk_device), nullptr,
                                    android::vold::cp_needsCheckpoint());
    if (setexeccon(nullptr)) {
        PLOG(ERROR) << "Failed to clear setexeccon";
        return false;
    }
    if (mount_rc != 0) {
        LOG(ERROR) << "fs_mgr_do_mount failed with rc " << mount_rc;
        return false;
    }
    LOG(DEBUG) << "Mounted " << mount_point;
    return true;
}

namespace android {
namespace vold {

// Note: It is possible to orphan a key if it is removed before deleting
// Update this once keymaster APIs change, and we have a proper commit.
static void commit_key(const std::string& dir) {
    while (!android::base::WaitForProperty("vold.checkpoint_committed", "1")) {
        LOG(ERROR) << "Wait for boot timed out";
    }
    Keymaster keymaster;
    auto keyPath = dir + "/" + kFn_keymaster_key_blob;
    auto newKeyPath = dir + "/" + kFn_keymaster_key_blob_upgraded;
    std::string key;

    if (!android::base::ReadFileToString(keyPath, &key)) {
        LOG(ERROR) << "Failed to read old key: " << dir;
        return;
    }
    if (rename(newKeyPath.c_str(), keyPath.c_str()) != 0) {
        PLOG(ERROR) << "Unable to move upgraded key to location: " << keyPath;
        return;
    }
    if (!keymaster.deleteKey(key)) {
        LOG(ERROR) << "Key deletion failed during upgrade, continuing anyway: " << dir;
    }
    LOG(INFO) << "Old Key deleted: " << dir;
}

static bool retrieveMetadataKey(bool create_if_absent, const std::string& key_path,
                                const std::string& tmp_path, KeyBuffer* key, bool keepOld) {
    if (pathExists(key_path)) {
        LOG(DEBUG) << "Key exists, using: " << key_path;
        if (!retrieveKey(key_path, kEmptyAuthentication, key, keepOld)) return false;
    } else {
        if (!create_if_absent) {
            LOG(ERROR) << "No key found in " << key_path;
            return false;
        }
        LOG(INFO) << "Creating new key in " << key_path;
        if (!randomKey(key)) return false;
        if (!storeKeyAtomically(key_path, tmp_path, kEmptyAuthentication, *key)) return false;
    }
    return true;
}

static bool read_key(const FstabEntry& data_rec, bool create_if_absent, KeyBuffer* key) {
    if (data_rec.metadata_key_dir.empty()) {
        LOG(ERROR) << "Failed to get metadata_key_dir";
        return false;
    }
    std::string metadata_key_dir = data_rec.metadata_key_dir;
    std::string sKey;
    auto dir = metadata_key_dir + "/key";
    LOG(DEBUG) << "metadata_key_dir/key: " << dir;
    if (fs_mkdirs(dir.c_str(), 0700)) {
        PLOG(ERROR) << "Creating directories: " << dir;
        return false;
    }
    auto temp = metadata_key_dir + "/tmp";
    auto newKeyPath = dir + "/" + kFn_keymaster_key_blob_upgraded;
    /* If we have a leftover upgraded key, delete it.
     * We either failed an update and must return to the old key,
     * or we rebooted before commiting the keys in a freak accident.
     * Either way, we can re-upgrade the key if we need to.
     */
    Keymaster keymaster;
    if (pathExists(newKeyPath)) {
        if (!android::base::ReadFileToString(newKeyPath, &sKey))
            LOG(ERROR) << "Failed to read old key: " << dir;
        else if (!keymaster.deleteKey(sKey))
            LOG(ERROR) << "Old key deletion failed, continuing anyway: " << dir;
        else
            unlink(newKeyPath.c_str());
    }
    bool needs_cp = cp_needsCheckpoint();
    if (!retrieveMetadataKey(create_if_absent, dir, temp, key, needs_cp)) return false;
    if (needs_cp && pathExists(newKeyPath)) std::thread(commit_key, dir).detach();
    return true;
}

}  // namespace vold
}  // namespace android

static bool get_number_of_sectors(const std::string& real_blkdev, uint64_t* nr_sec) {
    if (android::vold::GetBlockDev512Sectors(real_blkdev, nr_sec) != android::OK) {
        PLOG(ERROR) << "Unable to measure size of " << real_blkdev;
        return false;
    }
    return true;
}

static std::string lookup_cipher(const std::string& cipher_name, bool is_legacy) {
    if (is_legacy) {
        if (cipher_name.empty() || cipher_name == "aes-256-xts") {
            return "AES-256-XTS";
        }
    } else {
        if (cipher_name.empty() || cipher_name == "aes-256-xts") {
            return "aes-xts-plain64";
        } else if (cipher_name == "adiantum") {
            return "xchacha12,aes-adiantum-plain64";
        }
    }
    LOG(ERROR) << "No metadata cipher named " << cipher_name << " found, is_legacy=" << is_legacy;
    return "";
}

static bool create_crypto_blk_dev(const std::string& dm_name, const FstabEntry* data_rec,
                                  const KeyBuffer& key, std::string* crypto_blkdev) {
    uint64_t nr_sec;
    if (!get_number_of_sectors(data_rec->blk_device, &nr_sec)) return false;

    bool is_legacy;
    if (!DmTargetDefaultKey::IsLegacy(&is_legacy)) return false;

    auto cipher = lookup_cipher(data_rec->metadata_cipher, is_legacy);
    if (cipher.empty()) return false;

    KeyBuffer hex_key_buffer;
    if (android::vold::StrToHex(key, hex_key_buffer) != android::OK) {
        LOG(ERROR) << "Failed to turn key to hex";
        return false;
    }
    std::string hex_key(hex_key_buffer.data(), hex_key_buffer.size());

    // Non-legacy driver always sets DUN
    bool set_dun = !is_legacy || android::base::GetBoolProperty("ro.crypto.set_dun", false);
    if (!set_dun && data_rec->fs_mgr_flags.checkpoint_blk) {
        LOG(ERROR) << "Block checkpoints and metadata encryption require ro.crypto.set_dun option";
        return false;
    }

    DmTable table;
    table.Emplace<DmTargetDefaultKey>(0, nr_sec, cipher, hex_key, data_rec->blk_device, 0,
                                      is_legacy, set_dun);

    auto& dm = DeviceMapper::Instance();
    for (int i = 0;; i++) {
        if (dm.CreateDevice(dm_name, table)) {
            break;
        }
        if (i + 1 >= TABLE_LOAD_RETRIES) {
            PLOG(ERROR) << "Could not create default-key device " << dm_name;
            return false;
        }
        PLOG(INFO) << "Could not create default-key device, retrying";
        usleep(500000);
    }

    if (!dm.GetDmDevicePathByName(dm_name, crypto_blkdev)) {
        LOG(ERROR) << "Cannot retrieve default-key device status " << dm_name;
        return false;
    }
    return true;
}

bool fscrypt_mount_metadata_encrypted(const std::string& blk_device, const std::string& mount_point,
                                      bool needs_encrypt) {
    LOG(DEBUG) << "fscrypt_mount_metadata_encrypted: " << mount_point << " " << needs_encrypt;
    auto encrypted_state = android::base::GetProperty("ro.crypto.state", "");
    if (encrypted_state != "" && encrypted_state != "encrypted") {
        LOG(DEBUG) << "fscrypt_enable_crypto got unexpected starting state: " << encrypted_state;
        return false;
    }

    auto data_rec = GetEntryForMountPoint(&fstab_default, mount_point);
    if (!data_rec) {
        LOG(ERROR) << "Failed to get data_rec for " << mount_point;
        return false;
    }
    if (blk_device != data_rec->blk_device) {
        LOG(ERROR) << "blk_device " << blk_device << " does not match fstab entry "
                   << data_rec->blk_device << " for " << mount_point;
        return false;
    }
    KeyBuffer key;
    if (!read_key(*data_rec, needs_encrypt, &key)) return false;

    std::string crypto_blkdev;
    if (!create_crypto_blk_dev(kDmNameUserdata, data_rec, key, &crypto_blkdev)) return false;

    // FIXME handle the corrupt case
    if (needs_encrypt) {
        uint64_t nr_sec;
        if (!get_number_of_sectors(data_rec->blk_device, &nr_sec)) return false;
        LOG(INFO) << "Beginning inplace encryption, nr_sec: " << nr_sec;
        off64_t size_already_done = 0;
        auto rc = cryptfs_enable_inplace(crypto_blkdev.data(), blk_device.data(), nr_sec,
                                         &size_already_done, nr_sec, 0, false);
        if (rc != 0) {
            LOG(ERROR) << "Inplace crypto failed with code: " << rc;
            return false;
        }
        if (static_cast<uint64_t>(size_already_done) != nr_sec) {
            LOG(ERROR) << "Inplace crypto only got up to sector: " << size_already_done;
            return false;
        }
        LOG(INFO) << "Inplace encryption complete";
    }

    LOG(DEBUG) << "Mounting metadata-encrypted filesystem:" << mount_point;
    mount_via_fs_mgr(data_rec->mount_point.c_str(), crypto_blkdev.c_str());
    return true;
}
