blob: 07878effbabdbfe0bd8e6a37074974c1c3ff2d8f [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
Eric Carusocc7106c2017-04-27 14:22:42 -070013#include "debugd/src/error_utils.h"
David Purselle5ebdae2014-11-04 08:51:37 -080014#include "debugd/src/process_with_output.h"
15
16namespace debugd {
17
18namespace {
19
Ben Chan81905fb2017-02-08 22:03:11 -080020using ArgList = ProcessWithOutput::ArgList;
David Purselle5ebdae2014-11-04 08:51:37 -080021
David Pursellab8412f2014-12-09 13:41:12 -080022const char kDefaultRootPassword[] = "test0000";
23
David Purselle5ebdae2014-11-04 08:51:37 -080024const char kDevFeaturesErrorString[] = "org.chromium.debugd.error.DevFeatures";
25const char kRootfsLockedErrorString[] =
26 "Rootfs verification must be removed first";
27
28// Executes a helper process with the expectation that any message printed to
29// stderr indicates a failure that should be passed back over the D-Bus.
Eric Caruso8fe49c72017-04-25 10:43:59 -070030// Returns false if any errors launching the process occur. Returns true
31// otherwise, and sets |exit_status| if it isn't null.
32bool RunHelper(const std::string& command,
33 const ArgList& arguments,
34 bool requires_root,
35 const std::string* stdin,
36 int* exit_status,
Eric Carusocc7106c2017-04-27 14:22:42 -070037 brillo::ErrorPtr* error) {
David Purselle5ebdae2014-11-04 08:51:37 -080038 std::string stderr;
39 int result = ProcessWithOutput::RunHelper(command,
40 arguments,
41 requires_root,
42 stdin,
43 nullptr, // Don't need stdout.
44 &stderr,
45 error);
46 if (!stderr.empty()) {
Eric Carusocc7106c2017-04-27 14:22:42 -070047 DEBUGD_ADD_ERROR(error, 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 Carusocc7106c2017-04-27 14:22:42 -070056bool RemoveRootfsVerificationQuery(int* exit_status, brillo::ErrorPtr* 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 Carusocc7106c2017-04-27 14:22:42 -070064bool EnableBootFromUsbQuery(int* exit_status, brillo::ErrorPtr* 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 Carusocc7106c2017-04-27 14:22:42 -070072bool ConfigureSshServerQuery(int* exit_status, brillo::ErrorPtr* 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 Carusocc7106c2017-04-27 14:22:42 -070080bool EnableChromeRemoteDebuggingQuery(int* exit_status,
81 brillo::ErrorPtr* error) {
Eric Caruso75eda082017-04-25 11:37:26 -070082 return RunHelper("dev_features_chrome_remote_debugging", ArgList{"-q"},
83 false,
84 nullptr, // no stdin.
Eric Caruso8fe49c72017-04-25 10:43:59 -070085 exit_status,
86 error);
Eric Caruso75eda082017-04-25 11:37:26 -070087}
88
89bool SetUserPasswordQuery(const std::string& username,
90 bool system,
Eric Caruso8fe49c72017-04-25 10:43:59 -070091 int* exit_status,
Eric Carusocc7106c2017-04-27 14:22:42 -070092 brillo::ErrorPtr* error) {
Eric Caruso75eda082017-04-25 11:37:26 -070093 ArgList args{"-q", "--user=" + username};
94 if (system)
95 args.push_back("--system");
96
97 return RunHelper("dev_features_password", args,
98 true, // requires root to read either password file.
99 nullptr, // no stdin.
Eric Caruso8fe49c72017-04-25 10:43:59 -0700100 exit_status,
101 error);
Eric Caruso75eda082017-04-25 11:37:26 -0700102}
103
David Purselle5ebdae2014-11-04 08:51:37 -0800104} // namespace
105
Eric Carusocc7106c2017-04-27 14:22:42 -0700106bool DevFeaturesTool::RemoveRootfsVerification(brillo::ErrorPtr* error) const {
Eric Caruso8fe49c72017-04-25 10:43:59 -0700107 return RunHelper("dev_features_rootfs_verification", ArgList{},
108 true, // requires root for make_dev_ssd.sh script.
109 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::EnableBootFromUsb(brillo::ErrorPtr* error) const {
Eric Caruso8fe49c72017-04-25 10:43:59 -0700115 return RunHelper("dev_features_usb_boot", ArgList{},
116 true, // requires root for enable_dev_usb_boot script.
117 nullptr, // no stdin.
118 nullptr, // exit status doesn't matter.
119 error);
David Purselle5ebdae2014-11-04 08:51:37 -0800120}
121
Eric Carusocc7106c2017-04-27 14:22:42 -0700122bool DevFeaturesTool::ConfigureSshServer(brillo::ErrorPtr* error) const {
David Purselle5ebdae2014-11-04 08:51:37 -0800123 // SSH server configuration requires writing to rootfs.
Eric Caruso8fe49c72017-04-25 10:43:59 -0700124 int exit_status;
125 if (!RemoveRootfsVerificationQuery(&exit_status, error) || exit_status != 0) {
Eric Carusocc7106c2017-04-27 14:22:42 -0700126 DEBUGD_ADD_ERROR(error, kDevFeaturesErrorString, kRootfsLockedErrorString);
Eric Caruso8fe49c72017-04-25 10:43:59 -0700127 return false;
David Purselle5ebdae2014-11-04 08:51:37 -0800128 }
Eric Caruso8fe49c72017-04-25 10:43:59 -0700129
130 return RunHelper("dev_features_ssh", ArgList{},
131 true, // requires root to write to rootfs directories.
132 nullptr, // no stdin.
133 nullptr, // exit status doesn't matter.
134 error);
David Purselle5ebdae2014-11-04 08:51:37 -0800135}
136
Eric Carusocc7106c2017-04-27 14:22:42 -0700137bool DevFeaturesTool::EnableChromeRemoteDebugging(brillo::ErrorPtr* error)
138 const {
Eric Caruso8fe49c72017-04-25 10:43:59 -0700139 int exit_status;
140 if (!RemoveRootfsVerificationQuery(&exit_status, error) || exit_status != 0) {
Eric Carusocc7106c2017-04-27 14:22:42 -0700141 DEBUGD_ADD_ERROR(error, kDevFeaturesErrorString, kRootfsLockedErrorString);
Eric Caruso8fe49c72017-04-25 10:43:59 -0700142 return false;
Xiaohui Chena8bced82015-02-27 10:35:26 -0800143 }
Eric Caruso8fe49c72017-04-25 10:43:59 -0700144
145 return RunHelper("dev_features_chrome_remote_debugging", ArgList{},
146 true, // requires root to write to rootfs directories.
147 nullptr, // no stdin.
148 nullptr, // exit status doesn't matter.
149 error);
Xiaohui Chena8bced82015-02-27 10:35:26 -0800150}
151
Eric Caruso8fe49c72017-04-25 10:43:59 -0700152bool DevFeaturesTool::SetUserPassword(const std::string& username,
David Purselle5ebdae2014-11-04 08:51:37 -0800153 const std::string& password,
Eric Carusocc7106c2017-04-27 14:22:42 -0700154 brillo::ErrorPtr* error) const {
David Purselle5ebdae2014-11-04 08:51:37 -0800155 ArgList args{"--user=" + username};
156
157 // Set the devmode password regardless of rootfs verification state.
Eric Caruso8fe49c72017-04-25 10:43:59 -0700158 if (!RunHelper("dev_features_password", args,
159 true, // requires root to write devmode password file.
160 &password, // pipe the password through stdin.
161 nullptr, // exit status doesn't matter.
162 error)) {
163 return false;
David Purselle5ebdae2014-11-04 08:51:37 -0800164 }
Eric Caruso8fe49c72017-04-25 10:43:59 -0700165
166 // If rootfs is locked, don't bother setting the system password.
167 int exit_status;
168 if (!RemoveRootfsVerificationQuery(&exit_status, error) || exit_status != 0)
169 return true;
170
171 args.push_back("--system");
172 return RunHelper("dev_features_password", args,
173 true, // requires root to write system password file.
174 &password, // pipe the password through stdin.
175 nullptr, // exit status doesn't matter.
176 error);
David Purselle5ebdae2014-11-04 08:51:37 -0800177}
178
Eric Caruso8fe49c72017-04-25 10:43:59 -0700179bool DevFeaturesTool::EnableChromeDevFeatures(const std::string& root_password,
Eric Carusocc7106c2017-04-27 14:22:42 -0700180 brillo::ErrorPtr* error) const {
Eric Caruso8fe49c72017-04-25 10:43:59 -0700181 if (!EnableBootFromUsb(error))
182 return false;
183
184 if (!ConfigureSshServer(error))
185 return false;
186
187 return SetUserPassword(
188 "root",
189 root_password.empty() ? kDefaultRootPassword : root_password,
190 error);
David Purselle5ebdae2014-11-04 08:51:37 -0800191}
192
193namespace {
194
195struct Query {
Eric Caruso8fe49c72017-04-25 10:43:59 -0700196 // The callback should launch the query program. If launching fails, return
197 // false and set the error. If it succeeds, put the exit status in the
198 // integer out-argument.
Eric Carusocc7106c2017-04-27 14:22:42 -0700199 using Function = base::Callback<bool(int*, brillo::ErrorPtr*)>;
David Purselle5ebdae2014-11-04 08:51:37 -0800200
201 Function function;
202 DevFeatureFlag flag;
203};
204
205} // namespace
206
Eric Caruso8fe49c72017-04-25 10:43:59 -0700207bool DevFeaturesTool::QueryDevFeatures(int32_t* flags,
Eric Carusocc7106c2017-04-27 14:22:42 -0700208 brillo::ErrorPtr* error) const {
Eric Caruso8fe49c72017-04-25 10:43:59 -0700209 DCHECK(flags);
David Purselle5ebdae2014-11-04 08:51:37 -0800210 Query queries[] = {
Eric Caruso75eda082017-04-25 11:37:26 -0700211 {base::Bind(&RemoveRootfsVerificationQuery),
212 DEV_FEATURE_ROOTFS_VERIFICATION_REMOVED},
213 {base::Bind(&EnableBootFromUsbQuery),
214 DEV_FEATURE_BOOT_FROM_USB_ENABLED},
215 {base::Bind(&EnableChromeRemoteDebuggingQuery),
216 DEV_FEATURE_CHROME_REMOTE_DEBUGGING_ENABLED},
217 {base::Bind(&ConfigureSshServerQuery),
218 DEV_FEATURE_SSH_SERVER_CONFIGURED},
219 {base::Bind(&SetUserPasswordQuery, "root", /* system = */ false),
220 DEV_FEATURE_DEV_MODE_ROOT_PASSWORD_SET},
221 {base::Bind(&SetUserPasswordQuery, "root", /* system = */ true),
222 DEV_FEATURE_SYSTEM_ROOT_PASSWORD_SET}
David Purselle5ebdae2014-11-04 08:51:37 -0800223 };
224
Eric Caruso8fe49c72017-04-25 10:43:59 -0700225 int32_t result_flags = 0;
David Purselle5ebdae2014-11-04 08:51:37 -0800226 for (const auto& query : queries) {
Eric Caruso8fe49c72017-04-25 10:43:59 -0700227 int exit_status;
228 if (!query.function.Run(&exit_status, error)) {
229 // D-Bus is only set up to handle a single error so exit as soon as we
230 // hit one.
231 return false;
232 }
233 if (exit_status == 0)
234 result_flags |= query.flag;
David Purselle5ebdae2014-11-04 08:51:37 -0800235 }
Eric Caruso8fe49c72017-04-25 10:43:59 -0700236 *flags = result_flags;
237 return true;
David Purselle5ebdae2014-11-04 08:51:37 -0800238}
239
240} // namespace debugd