blob: c3f35d448f4b5f8ad6cf5b4a7b7a40229014d5a1 [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>
David Purselle5ebdae2014-11-04 08:51:37 -080011#include <chromeos/dbus/service_constants.h>
12
13#include "debugd/src/process_with_output.h"
14
15namespace debugd {
16
17namespace {
18
Ben Chan81905fb2017-02-08 22:03:11 -080019using ArgList = ProcessWithOutput::ArgList;
David Purselle5ebdae2014-11-04 08:51:37 -080020
David Pursellab8412f2014-12-09 13:41:12 -080021const char kDefaultRootPassword[] = "test0000";
22
David Purselle5ebdae2014-11-04 08:51:37 -080023const char kDevFeaturesErrorString[] = "org.chromium.debugd.error.DevFeatures";
24const char kRootfsLockedErrorString[] =
25 "Rootfs verification must be removed first";
26
27// Executes a helper process with the expectation that any message printed to
28// stderr indicates a failure that should be passed back over the D-Bus.
Eric Caruso8fe49c72017-04-25 10:43:59 -070029// Returns false if any errors launching the process occur. Returns true
30// otherwise, and sets |exit_status| if it isn't null.
31bool RunHelper(const std::string& command,
32 const ArgList& arguments,
33 bool requires_root,
34 const std::string* stdin,
35 int* exit_status,
36 DBus::Error* error) {
David Purselle5ebdae2014-11-04 08:51:37 -080037 std::string stderr;
38 int result = ProcessWithOutput::RunHelper(command,
39 arguments,
40 requires_root,
41 stdin,
42 nullptr, // Don't need stdout.
43 &stderr,
44 error);
45 if (!stderr.empty()) {
Eric Caruso8fe49c72017-04-25 10:43:59 -070046 if (error && !error->is_set())
David Purselle5ebdae2014-11-04 08:51:37 -080047 error->set(kDevFeaturesErrorString, stderr.c_str());
Eric Caruso8fe49c72017-04-25 10:43:59 -070048 return false;
David Purselle5ebdae2014-11-04 08:51:37 -080049 }
Eric Caruso8fe49c72017-04-25 10:43:59 -070050
51 if (exit_status)
52 *exit_status = result;
53 return true;
David Purselle5ebdae2014-11-04 08:51:37 -080054}
55
Eric Caruso8fe49c72017-04-25 10:43:59 -070056bool RemoveRootfsVerificationQuery(int* exit_status, DBus::Error* error) {
Eric Caruso75eda082017-04-25 11:37:26 -070057 return RunHelper("dev_features_rootfs_verification", ArgList{"-q"},
58 true, // requires root to check if / is writable by root.
59 nullptr, // no stdin.
Eric Caruso8fe49c72017-04-25 10:43:59 -070060 exit_status,
61 error);
Eric Caruso75eda082017-04-25 11:37:26 -070062}
63
Eric Caruso8fe49c72017-04-25 10:43:59 -070064bool EnableBootFromUsbQuery(int* exit_status, DBus::Error* error) {
Eric Caruso75eda082017-04-25 11:37:26 -070065 return RunHelper("dev_features_usb_boot", ArgList{"-q"},
66 true, // requires root for crossystem queries.
67 nullptr, // no stdin.
Eric Caruso8fe49c72017-04-25 10:43:59 -070068 exit_status,
69 error);
Eric Caruso75eda082017-04-25 11:37:26 -070070}
71
Eric Caruso8fe49c72017-04-25 10:43:59 -070072bool ConfigureSshServerQuery(int* exit_status, DBus::Error* error) {
Eric Caruso75eda082017-04-25 11:37:26 -070073 return RunHelper("dev_features_ssh", ArgList{"-q"},
74 true, // needs root to check for files in 700 folders.
75 nullptr, // no stdin.
Eric Caruso8fe49c72017-04-25 10:43:59 -070076 exit_status,
77 error);
Eric Caruso75eda082017-04-25 11:37:26 -070078}
79
Eric Caruso8fe49c72017-04-25 10:43:59 -070080bool EnableChromeRemoteDebuggingQuery(int* exit_status, DBus::Error* error) {
Eric Caruso75eda082017-04-25 11:37:26 -070081 return RunHelper("dev_features_chrome_remote_debugging", ArgList{"-q"},
82 false,
83 nullptr, // no stdin.
Eric Caruso8fe49c72017-04-25 10:43:59 -070084 exit_status,
85 error);
Eric Caruso75eda082017-04-25 11:37:26 -070086}
87
88bool SetUserPasswordQuery(const std::string& username,
89 bool system,
Eric Caruso8fe49c72017-04-25 10:43:59 -070090 int* exit_status,
Eric Caruso75eda082017-04-25 11:37:26 -070091 DBus::Error* error) {
92 ArgList args{"-q", "--user=" + username};
93 if (system)
94 args.push_back("--system");
95
96 return RunHelper("dev_features_password", args,
97 true, // requires root to read either password file.
98 nullptr, // no stdin.
Eric Caruso8fe49c72017-04-25 10:43:59 -070099 exit_status,
100 error);
Eric Caruso75eda082017-04-25 11:37:26 -0700101}
102
David Purselle5ebdae2014-11-04 08:51:37 -0800103} // namespace
104
Eric Caruso8fe49c72017-04-25 10:43:59 -0700105bool DevFeaturesTool::RemoveRootfsVerification(DBus::Error* error) const {
106 return RunHelper("dev_features_rootfs_verification", ArgList{},
107 true, // requires root for make_dev_ssd.sh script.
108 nullptr, // no stdin.
109 nullptr, // exit status doesn't matter.
110 error);
David Purselle5ebdae2014-11-04 08:51:37 -0800111}
112
Eric Caruso8fe49c72017-04-25 10:43:59 -0700113bool DevFeaturesTool::EnableBootFromUsb(DBus::Error* error) const {
114 return RunHelper("dev_features_usb_boot", ArgList{},
115 true, // requires root for enable_dev_usb_boot script.
116 nullptr, // no stdin.
117 nullptr, // exit status doesn't matter.
118 error);
David Purselle5ebdae2014-11-04 08:51:37 -0800119}
120
Eric Caruso8fe49c72017-04-25 10:43:59 -0700121bool DevFeaturesTool::ConfigureSshServer(DBus::Error* error) const {
David Purselle5ebdae2014-11-04 08:51:37 -0800122 // SSH server configuration requires writing to rootfs.
Eric Caruso8fe49c72017-04-25 10:43:59 -0700123 int exit_status;
124 if (!RemoveRootfsVerificationQuery(&exit_status, error) || exit_status != 0) {
David Purselle5ebdae2014-11-04 08:51:37 -0800125 error->set(kDevFeaturesErrorString, kRootfsLockedErrorString);
Eric Caruso8fe49c72017-04-25 10:43:59 -0700126 return false;
David Purselle5ebdae2014-11-04 08:51:37 -0800127 }
Eric Caruso8fe49c72017-04-25 10:43:59 -0700128
129 return RunHelper("dev_features_ssh", ArgList{},
130 true, // requires root to write to rootfs directories.
131 nullptr, // no stdin.
132 nullptr, // exit status doesn't matter.
133 error);
David Purselle5ebdae2014-11-04 08:51:37 -0800134}
135
Eric Caruso8fe49c72017-04-25 10:43:59 -0700136bool DevFeaturesTool::EnableChromeRemoteDebugging(DBus::Error* error) const {
137 int exit_status;
138 if (!RemoveRootfsVerificationQuery(&exit_status, error) || exit_status != 0) {
Xiaohui Chena8bced82015-02-27 10:35:26 -0800139 error->set(kDevFeaturesErrorString, kRootfsLockedErrorString);
Eric Caruso8fe49c72017-04-25 10:43:59 -0700140 return false;
Xiaohui Chena8bced82015-02-27 10:35:26 -0800141 }
Eric Caruso8fe49c72017-04-25 10:43:59 -0700142
143 return RunHelper("dev_features_chrome_remote_debugging", ArgList{},
144 true, // requires root to write to rootfs directories.
145 nullptr, // no stdin.
146 nullptr, // exit status doesn't matter.
147 error);
Xiaohui Chena8bced82015-02-27 10:35:26 -0800148}
149
Eric Caruso8fe49c72017-04-25 10:43:59 -0700150bool DevFeaturesTool::SetUserPassword(const std::string& username,
David Purselle5ebdae2014-11-04 08:51:37 -0800151 const std::string& password,
152 DBus::Error* error) const {
153 ArgList args{"--user=" + username};
154
155 // Set the devmode password regardless of rootfs verification state.
Eric Caruso8fe49c72017-04-25 10:43:59 -0700156 if (!RunHelper("dev_features_password", args,
157 true, // requires root to write devmode password file.
158 &password, // pipe the password through stdin.
159 nullptr, // exit status doesn't matter.
160 error)) {
161 return false;
David Purselle5ebdae2014-11-04 08:51:37 -0800162 }
Eric Caruso8fe49c72017-04-25 10:43:59 -0700163
164 // If rootfs is locked, don't bother setting the system password.
165 int exit_status;
166 if (!RemoveRootfsVerificationQuery(&exit_status, error) || exit_status != 0)
167 return true;
168
169 args.push_back("--system");
170 return RunHelper("dev_features_password", args,
171 true, // requires root to write system password file.
172 &password, // pipe the password through stdin.
173 nullptr, // exit status doesn't matter.
174 error);
David Purselle5ebdae2014-11-04 08:51:37 -0800175}
176
Eric Caruso8fe49c72017-04-25 10:43:59 -0700177bool DevFeaturesTool::EnableChromeDevFeatures(const std::string& root_password,
David Purselle5ebdae2014-11-04 08:51:37 -0800178 DBus::Error* error) const {
Eric Caruso8fe49c72017-04-25 10:43:59 -0700179 if (!EnableBootFromUsb(error))
180 return false;
181
182 if (!ConfigureSshServer(error))
183 return false;
184
185 return SetUserPassword(
186 "root",
187 root_password.empty() ? kDefaultRootPassword : root_password,
188 error);
David Purselle5ebdae2014-11-04 08:51:37 -0800189}
190
191namespace {
192
193struct Query {
Eric Caruso8fe49c72017-04-25 10:43:59 -0700194 // The callback should launch the query program. If launching fails, return
195 // false and set the error. If it succeeds, put the exit status in the
196 // integer out-argument.
197 using Function = base::Callback<bool(int*, DBus::Error*)>;
David Purselle5ebdae2014-11-04 08:51:37 -0800198
199 Function function;
200 DevFeatureFlag flag;
201};
202
203} // namespace
204
Eric Caruso8fe49c72017-04-25 10:43:59 -0700205bool DevFeaturesTool::QueryDevFeatures(int32_t* flags,
206 DBus::Error* error) const {
207 DCHECK(flags);
David Purselle5ebdae2014-11-04 08:51:37 -0800208 Query queries[] = {
Eric Caruso75eda082017-04-25 11:37:26 -0700209 {base::Bind(&RemoveRootfsVerificationQuery),
210 DEV_FEATURE_ROOTFS_VERIFICATION_REMOVED},
211 {base::Bind(&EnableBootFromUsbQuery),
212 DEV_FEATURE_BOOT_FROM_USB_ENABLED},
213 {base::Bind(&EnableChromeRemoteDebuggingQuery),
214 DEV_FEATURE_CHROME_REMOTE_DEBUGGING_ENABLED},
215 {base::Bind(&ConfigureSshServerQuery),
216 DEV_FEATURE_SSH_SERVER_CONFIGURED},
217 {base::Bind(&SetUserPasswordQuery, "root", /* system = */ false),
218 DEV_FEATURE_DEV_MODE_ROOT_PASSWORD_SET},
219 {base::Bind(&SetUserPasswordQuery, "root", /* system = */ true),
220 DEV_FEATURE_SYSTEM_ROOT_PASSWORD_SET}
David Purselle5ebdae2014-11-04 08:51:37 -0800221 };
222
Eric Caruso8fe49c72017-04-25 10:43:59 -0700223 int32_t result_flags = 0;
David Purselle5ebdae2014-11-04 08:51:37 -0800224 for (const auto& query : queries) {
Eric Caruso8fe49c72017-04-25 10:43:59 -0700225 int exit_status;
226 if (!query.function.Run(&exit_status, error)) {
227 // D-Bus is only set up to handle a single error so exit as soon as we
228 // hit one.
229 return false;
230 }
231 if (exit_status == 0)
232 result_flags |= query.flag;
David Purselle5ebdae2014-11-04 08:51:37 -0800233 }
Eric Caruso8fe49c72017-04-25 10:43:59 -0700234 *flags = result_flags;
235 return true;
David Purselle5ebdae2014-11-04 08:51:37 -0800236}
237
238} // namespace debugd