blob: 014e64a04b6d84438e51f3702e7bc1139ce645b4 [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
9#include <base/files/file_path.h>
10#include <base/files/file_util.h>
11#include <chromeos/dbus/service_constants.h>
12
13#include "debugd/src/process_with_output.h"
14
15namespace debugd {
16
17namespace {
18
19typedef ProcessWithOutput::ArgList ArgList;
20
21const char kDevFeaturesErrorString[] = "org.chromium.debugd.error.DevFeatures";
22const char kRootfsLockedErrorString[] =
23 "Rootfs verification must be removed first";
24
25// Executes a helper process with the expectation that any message printed to
26// stderr indicates a failure that should be passed back over the D-Bus.
27int RunHelper(const std::string& command,
28 const ArgList& arguments,
29 bool requires_root,
30 const std::string* stdin,
31 DBus::Error* error) {
32 std::string stderr;
33 int result = ProcessWithOutput::RunHelper(command,
34 arguments,
35 requires_root,
36 stdin,
37 nullptr, // Don't need stdout.
38 &stderr,
39 error);
40 if (!stderr.empty()) {
41 if (error && !error->is_set()) {
42 error->set(kDevFeaturesErrorString, stderr.c_str());
43 }
44 }
45 return result;
46}
47
48} // namespace
49
50void DevFeaturesTool::RemoveRootfsVerification(DBus::Error* error) const {
51 RunHelper("dev_features_rootfs_verification", ArgList{},
52 true, // requires root for make_dev_ssd.sh script.
53 nullptr, // no stdin.
54 error);
55}
56
57bool DevFeaturesTool::RemoveRootfsVerificationQuery(DBus::Error* error) const {
58 return RunHelper("dev_features_rootfs_verification", ArgList{"-q"},
59 true, // requires root to check if / is writable by root.
60 nullptr, // no stdin.
61 error) == 0;
62}
63
64void DevFeaturesTool::EnableBootFromUsb(DBus::Error* error) const {
65 RunHelper("dev_features_usb_boot", ArgList{},
66 true, // requires root for enable_dev_usb_boot script.
67 nullptr, // no stdin.
68 error);
69}
70
71bool DevFeaturesTool::EnableBootFromUsbQuery(DBus::Error* error) const {
72 return RunHelper("dev_features_usb_boot", ArgList{"-q"},
73 true, // requires root for crossystem queries.
74 nullptr, // no stdin.
75 error) == 0;
76}
77
78void DevFeaturesTool::ConfigureSshServer(DBus::Error* error) const {
79 // SSH server configuration requires writing to rootfs.
80 if (RemoveRootfsVerificationQuery(error)) {
81 RunHelper("dev_features_ssh", ArgList{},
82 true, // requires root to write to rootfs directories.
83 nullptr, // no stdin.
84 error);
85 } else if (!error->is_set()) {
86 error->set(kDevFeaturesErrorString, kRootfsLockedErrorString);
87 }
88}
89
90bool DevFeaturesTool::ConfigureSshServerQuery(DBus::Error* error) const {
91 return RunHelper("dev_features_ssh", ArgList{"-q"},
92 true, // needs root to check for files in 700 folders.
93 nullptr, // no stdin.
94 error) == 0;
95}
96
97void DevFeaturesTool::SetUserPassword(const std::string& username,
98 const std::string& password,
99 DBus::Error* error) const {
100 ArgList args{"--user=" + username};
101
102 // Set the devmode password regardless of rootfs verification state.
103 RunHelper("dev_features_password", args,
104 true, // requires root to write devmode password file.
105 &password, // pipe the password through stdin.
106 error);
107 if (!error->is_set()) {
108 // If rootfs is unlocked, we should set the system password as well.
109 if (RemoveRootfsVerificationQuery(error)) {
110 args.push_back("--system");
111 RunHelper("dev_features_password", args,
112 true, // requires root to write system password file.
113 &password, // pipe the password through stdin.
114 error);
115 }
116 }
117}
118
119bool DevFeaturesTool::SetUserPasswordQuery(const std::string& username,
120 bool system,
121 DBus::Error* error) const {
122 ArgList args{"-q", "--user=" + username};
123 if (system) {
124 args.push_back("--system");
125 }
126 return RunHelper("dev_features_password", args,
127 true, // requires root to read either password file.
128 nullptr, // no stdin.
129 error) == 0;
130}
131
132void DevFeaturesTool::EnableChromeDevFeatures(const std::string& root_password,
133 DBus::Error* error) const {
134 EnableBootFromUsb(error);
135 if (error->is_set()) {
136 return;
137 }
138 ConfigureSshServer(error);
139 if (error->is_set()) {
140 return;
141 }
142 SetUserPassword("root", root_password, error);
143 if (error->is_set()) {
144 return;
145 }
146}
147
148namespace {
149
150struct Query {
151 typedef std::function<bool(void)> Function;
152
153 Query(Function _function, DevFeatureFlag _flag)
154 : function(_function), flag(_flag) {
155 }
156
157 Function function;
158 DevFeatureFlag flag;
159};
160
161} // namespace
162
163int32_t DevFeaturesTool::QueryDevFeatures(DBus::Error* error) const {
164 Query queries[] = {
165 Query(std::bind(&DevFeaturesTool::RemoveRootfsVerificationQuery,
166 this, error),
167 DEV_FEATURE_ROOTFS_VERIFICATION_REMOVED),
168 Query(std::bind(&DevFeaturesTool::EnableBootFromUsbQuery,
169 this, error),
170 DEV_FEATURE_BOOT_FROM_USB_ENABLED),
171 Query(std::bind(&DevFeaturesTool::ConfigureSshServerQuery,
172 this, error),
173 DEV_FEATURE_SSH_SERVER_CONFIGURED),
174 Query(std::bind(&DevFeaturesTool::SetUserPasswordQuery,
175 this, "root", false, error), // false = devmode password.
176 DEV_FEATURE_DEV_MODE_ROOT_PASSWORD_SET),
177 Query(std::bind(&DevFeaturesTool::SetUserPasswordQuery,
178 this, "root", true, error), // true = system password.
179 DEV_FEATURE_SYSTEM_ROOT_PASSWORD_SET)
180 };
181
182 int32_t flags = 0;
183 for (const auto& query : queries) {
184 if (query.function()) {
185 flags |= query.flag;
186 }
187 // D-Bus is only set up to handle a single error so exit as soon as we
188 // hit one.
189 if (error->is_set()) {
190 return 0;
191 }
192 }
193 return flags;
194}
195
196} // namespace debugd