blob: 266bab586b5ff6333ea54f8bcb00ac278c6bb9ea [file] [log] [blame] [edit]
// Copyright 2014 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 "debugd/src/dev_mode_no_owner_restriction.h"
#include <memory>
#include <string>
#include <vector>
#include <chromeos/dbus/service_constants.h>
#include <cryptohome/proto_bindings/UserDataAuth.pb.h>
#include <dbus/bus.h>
#include <dbus/message.h>
#include <dbus/object_path.h>
#include <dbus/object_proxy.h>
#include <google/protobuf/message_lite.h>
#include <user_data_auth-client/user_data_auth/dbus-proxies.h>
#include "debugd/src/error_utils.h"
#include "debugd/src/process_with_output.h"
#include "rpc.pb.h" // NOLINT(build/include_directory)
namespace debugd {
namespace {
const char kAccessDeniedErrorString[] =
"org.chromium.debugd.error.AccessDenied";
const char kDevModeAccessErrorString[] =
"Use of this tool is restricted to dev mode.";
const char kOwnerAccessErrorString[] =
"Unavailable after device has an owner or boot lockbox is finalized.";
const char kOwnerQueryErrorString[] =
"Error encountered when querying D-Bus, cryptohome may be busy.";
// Queries the cryptohome GetLoginStatus D-Bus interface.
//
// Handles lower-level logic for dbus methods and the cryptohome protobuf
// classes. Cryptohome protobuf responses work by extending the BaseReply class,
// so if an error occurs it's possible to get a reply that does not contain the
// GetLoginStatusReply extension.
//
// |reply| will be filled if a response was received regardless of extension,
// but the function will only return true if reply is filled and has the
// correct GetLoginStatusReply extension.
bool CryptohomeGetLoginStatus(dbus::Bus* bus,
user_data_auth::GetLoginStatusReply* reply) {
org::chromium::CryptohomeMiscInterfaceProxy proxy(bus);
user_data_auth::GetLoginStatusRequest request;
brillo::ErrorPtr error;
bool success = proxy.GetLoginStatus(
request, reply, &error, user_data_auth::kUserDataAuthServiceTimeoutInMs);
if (!success || error) {
return false;
}
return true;
}
} // namespace
DevModeNoOwnerRestriction::DevModeNoOwnerRestriction(
scoped_refptr<dbus::Bus> bus)
: bus_(bus) {}
bool DevModeNoOwnerRestriction::AllowToolUse(brillo::ErrorPtr* error) {
// Check dev mode first to avoid unnecessary cryptohome query delays.
if (!InDevMode()) {
DEBUGD_ADD_ERROR(error, kAccessDeniedErrorString,
kDevModeAccessErrorString);
return false;
}
bool owner_exists, boot_lockbox_finalized;
if (!GetOwnerAndLockboxStatus(&owner_exists, &boot_lockbox_finalized)) {
// We want to specifically indicate when the query failed since it may
// mean that cryptohome is busy and could be tried again later.
DEBUGD_ADD_ERROR(error, kAccessDeniedErrorString, kOwnerQueryErrorString);
return false;
}
if (owner_exists || boot_lockbox_finalized) {
DEBUGD_ADD_ERROR(error, kAccessDeniedErrorString, kOwnerAccessErrorString);
return false;
}
return true;
}
bool DevModeNoOwnerRestriction::InDevMode() const {
// The is_developer_end_user script provides a common way to access this
// information rather than duplicating logic here.
return ProcessWithOutput::RunProcess("/usr/sbin/is_developer_end_user",
ProcessWithOutput::ArgList{},
true, // needs root to run properly.
false, // disable_sandbox.
nullptr, // no stdin.
nullptr, // no stdout.
nullptr, // no stderr.
nullptr) == 0; // no D-Bus error.
}
// Checks for owner user and boot lockbox status.
//
// This function handles the high-level code of checking the cryptohome
// protocol buffer response. Lower-level details of sending the D-Bus function
// and parsing the protocol buffer are handled in CryptohomeGetLoginStatus().
//
// If cryptohome was queried successfully, returns true and |owner_user_exists|
// and |boot_lockbox_finalized| are updated.
bool DevModeNoOwnerRestriction::GetOwnerAndLockboxStatus(
bool* owner_user_exists, bool* boot_lockbox_finalized) {
user_data_auth::GetLoginStatusReply reply;
if (CryptohomeGetLoginStatus(bus_.get(), &reply)) {
*owner_user_exists = reply.owner_user_exists();
// boot_lockbox_finalized is deprecated and always sets to false.
// See definition of user_data_auth::GetLoginStatusReply for more
// information.
*boot_lockbox_finalized = false;
return true;
}
return false;
}
} // namespace debugd