//
// Copyright (C) 2015 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 "attestation/server/database_impl.h"

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

#include <string>

#include <base/files/file_path.h>
#include <base/files/file_util.h>
#include <base/files/important_file_writer.h>
#include <base/logging.h>
#include <base/stl_util.h>
#include <brillo/secure_blob.h>

using base::FilePath;

namespace {

const char kDatabasePath[] =
    "/mnt/stateful_partition/unencrypted/preserve/attestation.epb";
const mode_t kDatabasePermissions = 0600;

// A base::FilePathWatcher::Callback that just relays to |callback|.
void FileWatcherCallback(const base::Closure& callback, const FilePath&, bool) {
  callback.Run();
}

}  // namespace

namespace attestation {

DatabaseImpl::DatabaseImpl(CryptoUtility* crypto) : io_(this), crypto_(crypto) {
}

DatabaseImpl::~DatabaseImpl() {
  brillo::SecureMemset(string_as_array(&database_key_), 0,
                       database_key_.size());
}

void DatabaseImpl::Initialize() {
  // Start thread-checking now.
  thread_checker_.DetachFromThread();
  DCHECK(thread_checker_.CalledOnValidThread());
  io_->Watch(base::Bind(base::IgnoreResult(&DatabaseImpl::Reload),
                        base::Unretained(this)));
  if (!Reload()) {
    LOG(WARNING) << "Creating new attestation database.";
  }
}

const AttestationDatabase& DatabaseImpl::GetProtobuf() const {
  DCHECK(thread_checker_.CalledOnValidThread());
  return protobuf_;
}

AttestationDatabase* DatabaseImpl::GetMutableProtobuf() {
  DCHECK(thread_checker_.CalledOnValidThread());
  return &protobuf_;
}

bool DatabaseImpl::SaveChanges() {
  DCHECK(thread_checker_.CalledOnValidThread());
  std::string buffer;
  if (!EncryptProtobuf(&buffer)) {
    return false;
  }
  return io_->Write(buffer);
}

bool DatabaseImpl::Reload() {
  DCHECK(thread_checker_.CalledOnValidThread());
  LOG(INFO) << "Loading attestation database.";
  std::string buffer;
  if (!io_->Read(&buffer)) {
    return false;
  }
  return DecryptProtobuf(buffer);
}

bool DatabaseImpl::Read(std::string* data) {
  const int kMask = base::FILE_PERMISSION_OTHERS_MASK;
  FilePath path(kDatabasePath);
  int permissions = 0;
  if (base::GetPosixFilePermissions(path, &permissions) &&
      (permissions & kMask) != 0) {
    base::SetPosixFilePermissions(path, permissions & ~kMask);
  }
  return base::ReadFileToString(path, data);
}

bool DatabaseImpl::Write(const std::string& data) {
  FilePath file_path(kDatabasePath);
  if (!base::CreateDirectory(file_path.DirName())) {
    LOG(ERROR) << "Cannot create directory: " << file_path.DirName().value();
    return false;
  }
  if (!base::ImportantFileWriter::WriteFileAtomically(file_path, data)) {
    LOG(ERROR) << "Failed to write file: " << file_path.value();
    return false;
  }
  if (!base::SetPosixFilePermissions(file_path, kDatabasePermissions)) {
    LOG(ERROR) << "Failed to set permissions for file: " << file_path.value();
    return false;
  }
  // Sync the parent directory.
  std::string dir_name = file_path.DirName().value();
  int dir_fd = HANDLE_EINTR(open(dir_name.c_str(), O_RDONLY|O_DIRECTORY));
  if (dir_fd < 0) {
    PLOG(WARNING) << "Could not open " << dir_name << " for syncing";
    return false;
  }
  // POSIX specifies EINTR as a possible return value of fsync().
  int result = HANDLE_EINTR(fsync(dir_fd));
  if (result < 0) {
    PLOG(WARNING) << "Failed to sync " << dir_name;
    close(dir_fd);
    return false;
  }
  // close() may not be retried on error.
  result = IGNORE_EINTR(close(dir_fd));
  if (result < 0) {
    PLOG(WARNING) << "Failed to close after sync " << dir_name;
    return false;
  }
  return true;
}

void DatabaseImpl::Watch(const base::Closure& callback) {
  if (!file_watcher_) {
    file_watcher_.reset(new base::FilePathWatcher());
    file_watcher_->Watch(FilePath(kDatabasePath), false,
                         base::Bind(&FileWatcherCallback, callback));
  }
}

bool DatabaseImpl::EncryptProtobuf(std::string* encrypted_output) {
  std::string serial_proto;
  if (!protobuf_.SerializeToString(&serial_proto)) {
    LOG(ERROR) << "Failed to serialize db.";
    return false;
  }
  if (database_key_.empty() || sealed_database_key_.empty()) {
    if (!crypto_->CreateSealedKey(&database_key_, &sealed_database_key_)) {
      LOG(ERROR) << "Failed to generate database key.";
      return false;
    }
  }
  if (!crypto_->EncryptData(serial_proto, database_key_, sealed_database_key_,
                            encrypted_output)) {
    LOG(ERROR) << "Attestation: Failed to encrypt database.";
    return false;
  }
  return true;
}

bool DatabaseImpl::DecryptProtobuf(const std::string& encrypted_input) {
  if (!crypto_->UnsealKey(encrypted_input, &database_key_,
                          &sealed_database_key_)) {
    LOG(ERROR) << "Attestation: Could not unseal decryption key.";
    return false;
  }
  std::string serial_proto;
  if (!crypto_->DecryptData(encrypted_input, database_key_, &serial_proto)) {
    LOG(ERROR) << "Attestation: Failed to decrypt database.";
    return false;
  }
  if (!protobuf_.ParseFromString(serial_proto)) {
    // Previously the DB was encrypted with CryptoLib::AesEncrypt which appends
    // a SHA-1.  This can be safely ignored.
    const size_t kLegacyJunkSize = 20;
    if (serial_proto.size() < kLegacyJunkSize ||
        !protobuf_.ParseFromArray(serial_proto.data(),
                                  serial_proto.length() - kLegacyJunkSize)) {
      LOG(ERROR) << "Failed to parse database.";
      return false;
    }
  }
  return true;
}

}  // namespace attestation
