blob: 4c571d135b50086879a2eb019f962e503a1710b1 [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.
29int RunHelper(const std::string& command,
30 const ArgList& arguments,
31 bool requires_root,
32 const std::string* stdin,
33 DBus::Error* error) {
34 std::string stderr;
35 int result = ProcessWithOutput::RunHelper(command,
36 arguments,
37 requires_root,
38 stdin,
39 nullptr, // Don't need stdout.
40 &stderr,
41 error);
42 if (!stderr.empty()) {
43 if (error && !error->is_set()) {
44 error->set(kDevFeaturesErrorString, stderr.c_str());
45 }
46 }
47 return result;
48}
49
Eric Caruso75eda082017-04-25 11:37:26 -070050bool RemoveRootfsVerificationQuery(DBus::Error* error) {
51 return RunHelper("dev_features_rootfs_verification", ArgList{"-q"},
52 true, // requires root to check if / is writable by root.
53 nullptr, // no stdin.
54 error) == 0;
55}
56
57bool EnableBootFromUsbQuery(DBus::Error* error) {
58 return RunHelper("dev_features_usb_boot", ArgList{"-q"},
59 true, // requires root for crossystem queries.
60 nullptr, // no stdin.
61 error) == 0;
62}
63
64bool ConfigureSshServerQuery(DBus::Error* error) {
65 return RunHelper("dev_features_ssh", ArgList{"-q"},
66 true, // needs root to check for files in 700 folders.
67 nullptr, // no stdin.
68 error) == 0;
69}
70
71bool EnableChromeRemoteDebuggingQuery(DBus::Error* error) {
72 return RunHelper("dev_features_chrome_remote_debugging", ArgList{"-q"},
73 false,
74 nullptr, // no stdin.
75 error) == 0;
76}
77
78bool SetUserPasswordQuery(const std::string& username,
79 bool system,
80 DBus::Error* error) {
81 ArgList args{"-q", "--user=" + username};
82 if (system)
83 args.push_back("--system");
84
85 return RunHelper("dev_features_password", args,
86 true, // requires root to read either password file.
87 nullptr, // no stdin.
88 error) == 0;
89}
90
David Purselle5ebdae2014-11-04 08:51:37 -080091} // namespace
92
93void DevFeaturesTool::RemoveRootfsVerification(DBus::Error* error) const {
94 RunHelper("dev_features_rootfs_verification", ArgList{},
95 true, // requires root for make_dev_ssd.sh script.
96 nullptr, // no stdin.
97 error);
98}
99
David Purselle5ebdae2014-11-04 08:51:37 -0800100void DevFeaturesTool::EnableBootFromUsb(DBus::Error* error) const {
101 RunHelper("dev_features_usb_boot", ArgList{},
102 true, // requires root for enable_dev_usb_boot script.
103 nullptr, // no stdin.
104 error);
105}
106
David Purselle5ebdae2014-11-04 08:51:37 -0800107void DevFeaturesTool::ConfigureSshServer(DBus::Error* error) const {
108 // SSH server configuration requires writing to rootfs.
109 if (RemoveRootfsVerificationQuery(error)) {
110 RunHelper("dev_features_ssh", ArgList{},
111 true, // requires root to write to rootfs directories.
112 nullptr, // no stdin.
113 error);
114 } else if (!error->is_set()) {
115 error->set(kDevFeaturesErrorString, kRootfsLockedErrorString);
116 }
117}
118
Xiaohui Chena8bced82015-02-27 10:35:26 -0800119void DevFeaturesTool::EnableChromeRemoteDebugging(DBus::Error* error) const {
120 if (RemoveRootfsVerificationQuery(error)) {
121 RunHelper("dev_features_chrome_remote_debugging", ArgList{},
122 true, // requires root to write to rootfs directories.
123 nullptr, // no stdin.
124 error);
125 } else if (!error->is_set()) {
126 error->set(kDevFeaturesErrorString, kRootfsLockedErrorString);
127 }
128}
129
David Purselle5ebdae2014-11-04 08:51:37 -0800130void DevFeaturesTool::SetUserPassword(const std::string& username,
131 const std::string& password,
132 DBus::Error* error) const {
133 ArgList args{"--user=" + username};
134
135 // Set the devmode password regardless of rootfs verification state.
136 RunHelper("dev_features_password", args,
137 true, // requires root to write devmode password file.
138 &password, // pipe the password through stdin.
139 error);
140 if (!error->is_set()) {
141 // If rootfs is unlocked, we should set the system password as well.
142 if (RemoveRootfsVerificationQuery(error)) {
143 args.push_back("--system");
144 RunHelper("dev_features_password", args,
145 true, // requires root to write system password file.
146 &password, // pipe the password through stdin.
147 error);
148 }
149 }
150}
151
David Purselle5ebdae2014-11-04 08:51:37 -0800152void DevFeaturesTool::EnableChromeDevFeatures(const std::string& root_password,
153 DBus::Error* error) const {
154 EnableBootFromUsb(error);
155 if (error->is_set()) {
156 return;
157 }
158 ConfigureSshServer(error);
159 if (error->is_set()) {
160 return;
161 }
David Pursellab8412f2014-12-09 13:41:12 -0800162 SetUserPassword("root",
163 root_password.empty() ? kDefaultRootPassword : root_password,
164 error);
David Purselle5ebdae2014-11-04 08:51:37 -0800165}
166
167namespace {
168
169struct Query {
Eric Caruso75eda082017-04-25 11:37:26 -0700170 using Function = base::Callback<bool(DBus::Error*)>;
David Purselle5ebdae2014-11-04 08:51:37 -0800171
172 Function function;
173 DevFeatureFlag flag;
174};
175
176} // namespace
177
178int32_t DevFeaturesTool::QueryDevFeatures(DBus::Error* error) const {
179 Query queries[] = {
Eric Caruso75eda082017-04-25 11:37:26 -0700180 {base::Bind(&RemoveRootfsVerificationQuery),
181 DEV_FEATURE_ROOTFS_VERIFICATION_REMOVED},
182 {base::Bind(&EnableBootFromUsbQuery),
183 DEV_FEATURE_BOOT_FROM_USB_ENABLED},
184 {base::Bind(&EnableChromeRemoteDebuggingQuery),
185 DEV_FEATURE_CHROME_REMOTE_DEBUGGING_ENABLED},
186 {base::Bind(&ConfigureSshServerQuery),
187 DEV_FEATURE_SSH_SERVER_CONFIGURED},
188 {base::Bind(&SetUserPasswordQuery, "root", /* system = */ false),
189 DEV_FEATURE_DEV_MODE_ROOT_PASSWORD_SET},
190 {base::Bind(&SetUserPasswordQuery, "root", /* system = */ true),
191 DEV_FEATURE_SYSTEM_ROOT_PASSWORD_SET}
David Purselle5ebdae2014-11-04 08:51:37 -0800192 };
193
194 int32_t flags = 0;
195 for (const auto& query : queries) {
Eric Caruso75eda082017-04-25 11:37:26 -0700196 if (query.function.Run(error))
David Purselle5ebdae2014-11-04 08:51:37 -0800197 flags |= query.flag;
David Purselle5ebdae2014-11-04 08:51:37 -0800198 // D-Bus is only set up to handle a single error so exit as soon as we
199 // hit one.
Eric Caruso75eda082017-04-25 11:37:26 -0700200 if (error->is_set())
David Purselle5ebdae2014-11-04 08:51:37 -0800201 return 0;
David Purselle5ebdae2014-11-04 08:51:37 -0800202 }
203 return flags;
204}
205
206} // namespace debugd