blob: 4bda7e5d41a251098316b33320aaa712e1efa68e [file] [log] [blame]
// 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_features_tool.h"
#include <functional>
#include <base/files/file_path.h>
#include <base/files/file_util.h>
#include <chromeos/dbus/service_constants.h>
#include "debugd/src/process_with_output.h"
namespace debugd {
namespace {
typedef ProcessWithOutput::ArgList ArgList;
const char kDefaultRootPassword[] = "test0000";
const char kDevFeaturesErrorString[] = "org.chromium.debugd.error.DevFeatures";
const char kRootfsLockedErrorString[] =
"Rootfs verification must be removed first";
// Executes a helper process with the expectation that any message printed to
// stderr indicates a failure that should be passed back over the D-Bus.
int RunHelper(const std::string& command,
const ArgList& arguments,
bool requires_root,
const std::string* stdin,
DBus::Error* error) {
std::string stderr;
int result = ProcessWithOutput::RunHelper(command,
arguments,
requires_root,
stdin,
nullptr, // Don't need stdout.
&stderr,
error);
if (!stderr.empty()) {
if (error && !error->is_set()) {
error->set(kDevFeaturesErrorString, stderr.c_str());
}
}
return result;
}
} // namespace
void DevFeaturesTool::RemoveRootfsVerification(DBus::Error* error) const {
RunHelper("dev_features_rootfs_verification", ArgList{},
true, // requires root for make_dev_ssd.sh script.
nullptr, // no stdin.
error);
}
bool DevFeaturesTool::RemoveRootfsVerificationQuery(DBus::Error* error) const {
return RunHelper("dev_features_rootfs_verification", ArgList{"-q"},
true, // requires root to check if / is writable by root.
nullptr, // no stdin.
error) == 0;
}
void DevFeaturesTool::EnableBootFromUsb(DBus::Error* error) const {
RunHelper("dev_features_usb_boot", ArgList{},
true, // requires root for enable_dev_usb_boot script.
nullptr, // no stdin.
error);
}
bool DevFeaturesTool::EnableBootFromUsbQuery(DBus::Error* error) const {
return RunHelper("dev_features_usb_boot", ArgList{"-q"},
true, // requires root for crossystem queries.
nullptr, // no stdin.
error) == 0;
}
void DevFeaturesTool::ConfigureSshServer(DBus::Error* error) const {
// SSH server configuration requires writing to rootfs.
if (RemoveRootfsVerificationQuery(error)) {
RunHelper("dev_features_ssh", ArgList{},
true, // requires root to write to rootfs directories.
nullptr, // no stdin.
error);
} else if (!error->is_set()) {
error->set(kDevFeaturesErrorString, kRootfsLockedErrorString);
}
}
bool DevFeaturesTool::ConfigureSshServerQuery(DBus::Error* error) const {
return RunHelper("dev_features_ssh", ArgList{"-q"},
true, // needs root to check for files in 700 folders.
nullptr, // no stdin.
error) == 0;
}
void DevFeaturesTool::EnableChromeRemoteDebugging(DBus::Error* error) const {
if (RemoveRootfsVerificationQuery(error)) {
RunHelper("dev_features_chrome_remote_debugging", ArgList{},
true, // requires root to write to rootfs directories.
nullptr, // no stdin.
error);
} else if (!error->is_set()) {
error->set(kDevFeaturesErrorString, kRootfsLockedErrorString);
}
}
bool DevFeaturesTool::EnableChromeRemoteDebuggingQuery(
DBus::Error* error) const {
return RunHelper("dev_features_chrome_remote_debugging", ArgList{"-q"},
false,
nullptr, // no stdin.
error) == 0;
}
void DevFeaturesTool::SetUserPassword(const std::string& username,
const std::string& password,
DBus::Error* error) const {
ArgList args{"--user=" + username};
// Set the devmode password regardless of rootfs verification state.
RunHelper("dev_features_password", args,
true, // requires root to write devmode password file.
&password, // pipe the password through stdin.
error);
if (!error->is_set()) {
// If rootfs is unlocked, we should set the system password as well.
if (RemoveRootfsVerificationQuery(error)) {
args.push_back("--system");
RunHelper("dev_features_password", args,
true, // requires root to write system password file.
&password, // pipe the password through stdin.
error);
}
}
}
bool DevFeaturesTool::SetUserPasswordQuery(const std::string& username,
bool system,
DBus::Error* error) const {
ArgList args{"-q", "--user=" + username};
if (system) {
args.push_back("--system");
}
return RunHelper("dev_features_password", args,
true, // requires root to read either password file.
nullptr, // no stdin.
error) == 0;
}
void DevFeaturesTool::EnableChromeDevFeatures(const std::string& root_password,
DBus::Error* error) const {
EnableBootFromUsb(error);
if (error->is_set()) {
return;
}
ConfigureSshServer(error);
if (error->is_set()) {
return;
}
SetUserPassword("root",
root_password.empty() ? kDefaultRootPassword : root_password,
error);
}
namespace {
struct Query {
typedef std::function<bool(void)> Function;
Query(Function _function, DevFeatureFlag _flag)
: function(_function), flag(_flag) {
}
Function function;
DevFeatureFlag flag;
};
} // namespace
int32_t DevFeaturesTool::QueryDevFeatures(DBus::Error* error) const {
Query queries[] = {
Query(std::bind(&DevFeaturesTool::RemoveRootfsVerificationQuery,
this, error),
DEV_FEATURE_ROOTFS_VERIFICATION_REMOVED),
Query(std::bind(&DevFeaturesTool::EnableBootFromUsbQuery,
this, error),
DEV_FEATURE_BOOT_FROM_USB_ENABLED),
Query(std::bind(&DevFeaturesTool::EnableChromeRemoteDebuggingQuery,
this, error),
DEV_FEATURE_CHROME_REMOTE_DEBUGGING_ENABLED),
Query(std::bind(&DevFeaturesTool::ConfigureSshServerQuery,
this, error),
DEV_FEATURE_SSH_SERVER_CONFIGURED),
Query(std::bind(&DevFeaturesTool::SetUserPasswordQuery,
this, "root", false, error), // false = devmode password.
DEV_FEATURE_DEV_MODE_ROOT_PASSWORD_SET),
Query(std::bind(&DevFeaturesTool::SetUserPasswordQuery,
this, "root", true, error), // true = system password.
DEV_FEATURE_SYSTEM_ROOT_PASSWORD_SET)
};
int32_t flags = 0;
for (const auto& query : queries) {
if (query.function()) {
flags |= query.flag;
}
// D-Bus is only set up to handle a single error so exit as soon as we
// hit one.
if (error->is_set()) {
return 0;
}
}
return flags;
}
} // namespace debugd