blob: 9fae61e72934fc472e9a72367f47cf9bafcedf41 [file] [log] [blame]
David Purselle5ebdae2014-11-04 08:51:37 -08001// Copyright 2014 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "debugd/src/dev_features_tool.h"
6
7#include <functional>
8
Eric Caruso75eda082017-04-25 11:37:26 -07009#include <base/bind.h>
10#include <base/callback.h>
Qijiang Fan713061e2021-03-08 15:45:12 +090011#include <base/check.h>
David Purselle5ebdae2014-11-04 08:51:37 -080012#include <chromeos/dbus/service_constants.h>
13
Eric Carusocc7106c2017-04-27 14:22:42 -070014#include "debugd/src/error_utils.h"
David Purselle5ebdae2014-11-04 08:51:37 -080015#include "debugd/src/process_with_output.h"
16
17namespace debugd {
18
19namespace {
20
Ben Chan81905fb2017-02-08 22:03:11 -080021using ArgList = ProcessWithOutput::ArgList;
David Purselle5ebdae2014-11-04 08:51:37 -080022
David Pursellab8412f2014-12-09 13:41:12 -080023const char kDefaultRootPassword[] = "test0000";
24
David Purselle5ebdae2014-11-04 08:51:37 -080025const char kDevFeaturesErrorString[] = "org.chromium.debugd.error.DevFeatures";
26const char kRootfsLockedErrorString[] =
27 "Rootfs verification must be removed first";
28
29// Executes a helper process with the expectation that any message printed to
30// stderr indicates a failure that should be passed back over the D-Bus.
Eric Caruso8fe49c72017-04-25 10:43:59 -070031// Returns false if any errors launching the process occur. Returns true
32// otherwise, and sets |exit_status| if it isn't null.
33bool RunHelper(const std::string& command,
34 const ArgList& arguments,
35 bool requires_root,
36 const std::string* stdin,
37 int* exit_status,
Eric Carusocc7106c2017-04-27 14:22:42 -070038 brillo::ErrorPtr* error) {
David Purselle5ebdae2014-11-04 08:51:37 -080039 std::string stderr;
Tom Hughesd6c2d392020-08-24 18:12:11 -070040 int result =
41 ProcessWithOutput::RunHelper(command, arguments, requires_root, stdin,
42 nullptr, // Don't need stdout.
43 &stderr, error);
David Purselle5ebdae2014-11-04 08:51:37 -080044 if (!stderr.empty()) {
Eric Carusocc7106c2017-04-27 14:22:42 -070045 DEBUGD_ADD_ERROR(error, kDevFeaturesErrorString, stderr.c_str());
Eric Caruso8fe49c72017-04-25 10:43:59 -070046 return false;
David Purselle5ebdae2014-11-04 08:51:37 -080047 }
Eric Caruso8fe49c72017-04-25 10:43:59 -070048
49 if (exit_status)
50 *exit_status = result;
51 return true;
David Purselle5ebdae2014-11-04 08:51:37 -080052}
53
Eric Carusocc7106c2017-04-27 14:22:42 -070054bool RemoveRootfsVerificationQuery(int* exit_status, brillo::ErrorPtr* error) {
Eric Caruso75eda082017-04-25 11:37:26 -070055 return RunHelper("dev_features_rootfs_verification", ArgList{"-q"},
Tom Hughesd6c2d392020-08-24 18:12:11 -070056 true, // requires root to check if / is writable by root.
Eric Caruso75eda082017-04-25 11:37:26 -070057 nullptr, // no stdin.
Tom Hughesd6c2d392020-08-24 18:12:11 -070058 exit_status, error);
Eric Caruso75eda082017-04-25 11:37:26 -070059}
60
Eric Carusocc7106c2017-04-27 14:22:42 -070061bool EnableBootFromUsbQuery(int* exit_status, brillo::ErrorPtr* error) {
Eric Caruso75eda082017-04-25 11:37:26 -070062 return RunHelper("dev_features_usb_boot", ArgList{"-q"},
Tom Hughesd6c2d392020-08-24 18:12:11 -070063 true, // requires root for crossystem queries.
Eric Caruso75eda082017-04-25 11:37:26 -070064 nullptr, // no stdin.
Tom Hughesd6c2d392020-08-24 18:12:11 -070065 exit_status, error);
Eric Caruso75eda082017-04-25 11:37:26 -070066}
67
Eric Carusocc7106c2017-04-27 14:22:42 -070068bool ConfigureSshServerQuery(int* exit_status, brillo::ErrorPtr* error) {
Eric Caruso75eda082017-04-25 11:37:26 -070069 return RunHelper("dev_features_ssh", ArgList{"-q"},
Tom Hughesd6c2d392020-08-24 18:12:11 -070070 true, // needs root to check for files in 700 folders.
Eric Caruso75eda082017-04-25 11:37:26 -070071 nullptr, // no stdin.
Tom Hughesd6c2d392020-08-24 18:12:11 -070072 exit_status, error);
Eric Caruso75eda082017-04-25 11:37:26 -070073}
74
Eric Carusocc7106c2017-04-27 14:22:42 -070075bool EnableChromeRemoteDebuggingQuery(int* exit_status,
76 brillo::ErrorPtr* error) {
Tom Hughesd6c2d392020-08-24 18:12:11 -070077 return RunHelper("dev_features_chrome_remote_debugging", ArgList{"-q"}, false,
Eric Caruso75eda082017-04-25 11:37:26 -070078 nullptr, // no stdin.
Tom Hughesd6c2d392020-08-24 18:12:11 -070079 exit_status, error);
Eric Caruso75eda082017-04-25 11:37:26 -070080}
81
82bool SetUserPasswordQuery(const std::string& username,
83 bool system,
Eric Caruso8fe49c72017-04-25 10:43:59 -070084 int* exit_status,
Eric Carusocc7106c2017-04-27 14:22:42 -070085 brillo::ErrorPtr* error) {
Eric Caruso75eda082017-04-25 11:37:26 -070086 ArgList args{"-q", "--user=" + username};
87 if (system)
88 args.push_back("--system");
89
90 return RunHelper("dev_features_password", args,
Tom Hughesd6c2d392020-08-24 18:12:11 -070091 true, // requires root to read either password file.
Eric Caruso75eda082017-04-25 11:37:26 -070092 nullptr, // no stdin.
Tom Hughesd6c2d392020-08-24 18:12:11 -070093 exit_status, error);
Eric Caruso75eda082017-04-25 11:37:26 -070094}
95
David Purselle5ebdae2014-11-04 08:51:37 -080096} // namespace
97
Eric Carusocc7106c2017-04-27 14:22:42 -070098bool DevFeaturesTool::RemoveRootfsVerification(brillo::ErrorPtr* error) const {
Eric Caruso8fe49c72017-04-25 10:43:59 -070099 return RunHelper("dev_features_rootfs_verification", ArgList{},
Tom Hughesd6c2d392020-08-24 18:12:11 -0700100 true, // requires root for make_dev_ssd.sh script.
Eric Caruso8fe49c72017-04-25 10:43:59 -0700101 nullptr, // no stdin.
102 nullptr, // exit status doesn't matter.
103 error);
David Purselle5ebdae2014-11-04 08:51:37 -0800104}
105
Eric Carusocc7106c2017-04-27 14:22:42 -0700106bool DevFeaturesTool::EnableBootFromUsb(brillo::ErrorPtr* error) const {
Eric Caruso8fe49c72017-04-25 10:43:59 -0700107 return RunHelper("dev_features_usb_boot", ArgList{},
Tom Hughesd6c2d392020-08-24 18:12:11 -0700108 true, // requires root for enable_dev_usb_boot script.
Eric Caruso8fe49c72017-04-25 10:43:59 -0700109 nullptr, // no stdin.
110 nullptr, // exit status doesn't matter.
111 error);
David Purselle5ebdae2014-11-04 08:51:37 -0800112}
113
Eric Carusocc7106c2017-04-27 14:22:42 -0700114bool DevFeaturesTool::ConfigureSshServer(brillo::ErrorPtr* error) const {
David Purselle5ebdae2014-11-04 08:51:37 -0800115 // SSH server configuration requires writing to rootfs.
Eric Caruso8fe49c72017-04-25 10:43:59 -0700116 int exit_status;
117 if (!RemoveRootfsVerificationQuery(&exit_status, error) || exit_status != 0) {
Eric Carusocc7106c2017-04-27 14:22:42 -0700118 DEBUGD_ADD_ERROR(error, kDevFeaturesErrorString, kRootfsLockedErrorString);
Eric Caruso8fe49c72017-04-25 10:43:59 -0700119 return false;
David Purselle5ebdae2014-11-04 08:51:37 -0800120 }
Eric Caruso8fe49c72017-04-25 10:43:59 -0700121
122 return RunHelper("dev_features_ssh", ArgList{},
Tom Hughesd6c2d392020-08-24 18:12:11 -0700123 true, // requires root to write to rootfs directories.
Eric Caruso8fe49c72017-04-25 10:43:59 -0700124 nullptr, // no stdin.
125 nullptr, // exit status doesn't matter.
126 error);
David Purselle5ebdae2014-11-04 08:51:37 -0800127}
128
Tom Hughesd6c2d392020-08-24 18:12:11 -0700129bool DevFeaturesTool::EnableChromeRemoteDebugging(
130 brillo::ErrorPtr* error) const {
Eric Caruso8fe49c72017-04-25 10:43:59 -0700131 int exit_status;
132 if (!RemoveRootfsVerificationQuery(&exit_status, error) || exit_status != 0) {
Eric Carusocc7106c2017-04-27 14:22:42 -0700133 DEBUGD_ADD_ERROR(error, kDevFeaturesErrorString, kRootfsLockedErrorString);
Eric Caruso8fe49c72017-04-25 10:43:59 -0700134 return false;
Xiaohui Chena8bced82015-02-27 10:35:26 -0800135 }
Eric Caruso8fe49c72017-04-25 10:43:59 -0700136
137 return RunHelper("dev_features_chrome_remote_debugging", ArgList{},
Tom Hughesd6c2d392020-08-24 18:12:11 -0700138 true, // requires root to write to rootfs directories.
Eric Caruso8fe49c72017-04-25 10:43:59 -0700139 nullptr, // no stdin.
140 nullptr, // exit status doesn't matter.
141 error);
Xiaohui Chena8bced82015-02-27 10:35:26 -0800142}
143
Eric Caruso8fe49c72017-04-25 10:43:59 -0700144bool DevFeaturesTool::SetUserPassword(const std::string& username,
David Purselle5ebdae2014-11-04 08:51:37 -0800145 const std::string& password,
Eric Carusocc7106c2017-04-27 14:22:42 -0700146 brillo::ErrorPtr* error) const {
David Purselle5ebdae2014-11-04 08:51:37 -0800147 ArgList args{"--user=" + username};
148
149 // Set the devmode password regardless of rootfs verification state.
Eric Caruso8fe49c72017-04-25 10:43:59 -0700150 if (!RunHelper("dev_features_password", args,
Tom Hughesd6c2d392020-08-24 18:12:11 -0700151 true, // requires root to write devmode password file.
Eric Caruso8fe49c72017-04-25 10:43:59 -0700152 &password, // pipe the password through stdin.
Tom Hughesd6c2d392020-08-24 18:12:11 -0700153 nullptr, // exit status doesn't matter.
Eric Caruso8fe49c72017-04-25 10:43:59 -0700154 error)) {
155 return false;
David Purselle5ebdae2014-11-04 08:51:37 -0800156 }
Eric Caruso8fe49c72017-04-25 10:43:59 -0700157
158 // If rootfs is locked, don't bother setting the system password.
159 int exit_status;
160 if (!RemoveRootfsVerificationQuery(&exit_status, error) || exit_status != 0)
161 return true;
162
163 args.push_back("--system");
164 return RunHelper("dev_features_password", args,
Tom Hughesd6c2d392020-08-24 18:12:11 -0700165 true, // requires root to write system password file.
Eric Caruso8fe49c72017-04-25 10:43:59 -0700166 &password, // pipe the password through stdin.
Tom Hughesd6c2d392020-08-24 18:12:11 -0700167 nullptr, // exit status doesn't matter.
Eric Caruso8fe49c72017-04-25 10:43:59 -0700168 error);
David Purselle5ebdae2014-11-04 08:51:37 -0800169}
170
Eric Caruso8fe49c72017-04-25 10:43:59 -0700171bool DevFeaturesTool::EnableChromeDevFeatures(const std::string& root_password,
Eric Carusocc7106c2017-04-27 14:22:42 -0700172 brillo::ErrorPtr* error) const {
Eric Caruso8fe49c72017-04-25 10:43:59 -0700173 if (!EnableBootFromUsb(error))
174 return false;
175
176 if (!ConfigureSshServer(error))
177 return false;
178
179 return SetUserPassword(
Tom Hughesd6c2d392020-08-24 18:12:11 -0700180 "root", root_password.empty() ? kDefaultRootPassword : root_password,
Eric Caruso8fe49c72017-04-25 10:43:59 -0700181 error);
David Purselle5ebdae2014-11-04 08:51:37 -0800182}
183
184namespace {
185
186struct Query {
Eric Caruso8fe49c72017-04-25 10:43:59 -0700187 // The callback should launch the query program. If launching fails, return
188 // false and set the error. If it succeeds, put the exit status in the
189 // integer out-argument.
Eric Carusocc7106c2017-04-27 14:22:42 -0700190 using Function = base::Callback<bool(int*, brillo::ErrorPtr*)>;
David Purselle5ebdae2014-11-04 08:51:37 -0800191
192 Function function;
193 DevFeatureFlag flag;
194};
195
196} // namespace
197
Eric Caruso8fe49c72017-04-25 10:43:59 -0700198bool DevFeaturesTool::QueryDevFeatures(int32_t* flags,
Eric Carusocc7106c2017-04-27 14:22:42 -0700199 brillo::ErrorPtr* error) const {
Eric Caruso8fe49c72017-04-25 10:43:59 -0700200 DCHECK(flags);
David Purselle5ebdae2014-11-04 08:51:37 -0800201 Query queries[] = {
Eric Caruso75eda082017-04-25 11:37:26 -0700202 {base::Bind(&RemoveRootfsVerificationQuery),
Tom Hughesd6c2d392020-08-24 18:12:11 -0700203 DEV_FEATURE_ROOTFS_VERIFICATION_REMOVED},
204 {base::Bind(&EnableBootFromUsbQuery), DEV_FEATURE_BOOT_FROM_USB_ENABLED},
Eric Caruso75eda082017-04-25 11:37:26 -0700205 {base::Bind(&EnableChromeRemoteDebuggingQuery),
Tom Hughesd6c2d392020-08-24 18:12:11 -0700206 DEV_FEATURE_CHROME_REMOTE_DEBUGGING_ENABLED},
207 {base::Bind(&ConfigureSshServerQuery), DEV_FEATURE_SSH_SERVER_CONFIGURED},
Eric Caruso75eda082017-04-25 11:37:26 -0700208 {base::Bind(&SetUserPasswordQuery, "root", /* system = */ false),
Tom Hughesd6c2d392020-08-24 18:12:11 -0700209 DEV_FEATURE_DEV_MODE_ROOT_PASSWORD_SET},
Eric Caruso75eda082017-04-25 11:37:26 -0700210 {base::Bind(&SetUserPasswordQuery, "root", /* system = */ true),
Tom Hughesd6c2d392020-08-24 18:12:11 -0700211 DEV_FEATURE_SYSTEM_ROOT_PASSWORD_SET}};
David Purselle5ebdae2014-11-04 08:51:37 -0800212
Eric Caruso8fe49c72017-04-25 10:43:59 -0700213 int32_t result_flags = 0;
David Purselle5ebdae2014-11-04 08:51:37 -0800214 for (const auto& query : queries) {
Eric Caruso8fe49c72017-04-25 10:43:59 -0700215 int exit_status;
216 if (!query.function.Run(&exit_status, error)) {
217 // D-Bus is only set up to handle a single error so exit as soon as we
218 // hit one.
219 return false;
220 }
221 if (exit_status == 0)
222 result_flags |= query.flag;
David Purselle5ebdae2014-11-04 08:51:37 -0800223 }
Eric Caruso8fe49c72017-04-25 10:43:59 -0700224 *flags = result_flags;
225 return true;
David Purselle5ebdae2014-11-04 08:51:37 -0800226}
227
228} // namespace debugd