blob: 88e04dbf8ad0dcf0b652f9bbf85498569252f3f1 [file] [log] [blame]
// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "libpasswordprovider/password_provider.h"
#include <keyutils.h>
#include "base/logging.h"
#include "libpasswordprovider/password.h"
namespace password_provider {
namespace {
constexpr char kKeyringDescription[] = "password keyring";
constexpr char kKeyringKeyType[] = "keyring";
constexpr char kPasswordKeyDescription[] = "password";
constexpr char kPasswordKeyType[] = "user";
key_serial_t RequestKey(const char* type, const char* description) {
key_serial_t keyring_serial =
find_key_by_type_and_desc(kKeyringKeyType, kKeyringDescription, 0);
if (keyring_serial == -1) {
PLOG(ERROR) << "Error finding keyring.";
return keyring_serial;
}
return keyctl_search(keyring_serial, type, description, 0);
}
int RevokeKey(const char* type, const char* description) {
key_serial_t key_serial = RequestKey(type, description);
if (key_serial == -1) {
return errno;
}
int result = keyctl_revoke(key_serial);
if (result == -1) {
return errno;
}
return result;
}
void HandleKeyError(const char* type, const char* description) {
int result = RevokeKey(type, description);
if (result != 0) {
PLOG(ERROR) << "Error revoking key: " << description;
}
}
} // namespace
PasswordProvider::PasswordProvider() {}
bool PasswordProvider::SavePassword(const Password& password) const {
DCHECK_GT(password.size(), 0);
DCHECK(password.GetRaw());
key_serial_t keyring_id = add_key(kKeyringKeyType, kKeyringDescription, NULL,
0, KEY_SPEC_PROCESS_KEYRING);
if (keyring_id == -1) {
PLOG(ERROR) << "Error creating keyring.";
return false;
}
int result =
keyctl_setperm(keyring_id, KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ |
KEY_USR_SEARCH | KEY_USR_WRITE);
if (result == -1) {
PLOG(ERROR) << "Error setting permissions on keyring. ";
return false;
}
key_serial_t key_serial =
add_key(kPasswordKeyType, kPasswordKeyDescription, password.GetRaw(),
password.size(), keyring_id);
if (key_serial == -1) {
PLOG(ERROR) << "Error adding key to keyring.";
return false;
}
result =
keyctl_setperm(key_serial, KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ |
KEY_USR_SEARCH | KEY_USR_WRITE);
if (result == -1) {
PLOG(ERROR) << "Error setting permissions on key. ";
HandleKeyError(kPasswordKeyType, kPasswordKeyDescription);
return false;
}
return true;
}
std::unique_ptr<Password> PasswordProvider::GetPassword() const {
key_serial_t key_serial =
RequestKey(kPasswordKeyType, kPasswordKeyDescription);
if (key_serial == -1) {
PLOG(WARNING) << "Could not find key.";
return nullptr;
}
auto password = std::make_unique<Password>();
if (!password->Init()) {
LOG(ERROR) << "Error allocating buffer for password";
return nullptr;
}
int result =
keyctl_read(key_serial, password->GetMutableRaw(), password->max_size());
if (result > password->max_size()) {
LOG(ERROR) << "Password too large for buffer. Max size: "
<< password->max_size();
return nullptr;
}
if (result == -1) {
PLOG(ERROR) << "Error reading key.";
return nullptr;
}
password->SetSize(result);
return password;
}
bool PasswordProvider::DiscardPassword() const {
int result = RevokeKey(kPasswordKeyType, kPasswordKeyDescription);
if (result != 0) {
PLOG(ERROR) << "Error revoking key.";
return false;
}
return true;
}
} // namespace password_provider