| // Copyright 2018 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "oobe_config/load_oobe_config_rollback.h" |
| |
| #include <base/files/file_path.h> |
| #include <base/files/file_util.h> |
| #include <base/json/json_writer.h> |
| #include <base/values.h> |
| #include <power_manager-client/power_manager/dbus-constants.h> |
| |
| #include "oobe_config/oobe_config.h" |
| #include "oobe_config/rollback_constants.h" |
| #include "oobe_config/rollback_data.pb.h" |
| |
| using base::FilePath; |
| using std::string; |
| using std::unique_ptr; |
| |
| namespace oobe_config { |
| |
| LoadOobeConfigRollback::LoadOobeConfigRollback( |
| OobeConfig* oobe_config, |
| bool allow_unencrypted, |
| bool skip_reboot_for_testing, |
| org::chromium::PowerManagerProxy* power_manager_proxy) |
| : oobe_config_(oobe_config), |
| allow_unencrypted_(allow_unencrypted), |
| skip_reboot_for_testing_(skip_reboot_for_testing), |
| power_manager_proxy_(power_manager_proxy) {} |
| |
| bool LoadOobeConfigRollback::GetOobeConfigJson(string* config, |
| string* enrollment_domain) { |
| LOG(INFO) << "Looking for rollback state."; |
| |
| *config = ""; |
| *enrollment_domain = ""; |
| |
| // Precondition for running rollback. |
| if (!oobe_config_->FileExists(kRestoreTempPath)) { |
| LOG(ERROR) << "Restore destination path doesn't exist."; |
| return false; |
| } |
| |
| if (!(oobe_config_->CheckFirstStage() || oobe_config_->CheckThirdStage())) { |
| // We are not in a valid state to run either stage 1 or stage 3 of rollback |
| // this is either a real error or this is not a rollback. |
| |
| if (oobe_config_->CheckSecondStage()) { |
| // This shouldn't happen, the script failed to execute. We fail and return |
| // false. |
| LOG(ERROR) << "Rollback restore is in invalid state (stage 2)."; |
| metrics_.RecordRestoreResult(Metrics::OobeRestoreResult::kStage2Failure); |
| } |
| return false; |
| } |
| |
| if (oobe_config_->CheckFirstStage()) { |
| LOG(INFO) << "Starting rollback restore stage 1."; |
| |
| // In the first stage we decrypt the proto from kUnencryptedRollbackDataPath |
| // and save it unencrypted to kEncryptedStatefulRollbackDataPath. |
| bool restore_result; |
| if (allow_unencrypted_) { |
| restore_result = oobe_config_->UnencryptedRollbackRestore(); |
| } else { |
| restore_result = oobe_config_->EncryptedRollbackRestore(); |
| } |
| |
| if (!restore_result) { |
| LOG(ERROR) << "Failed to restore rollback data"; |
| metrics_.RecordRestoreResult(Metrics::OobeRestoreResult::kStage1Failure); |
| return false; |
| } |
| |
| // We create kFirstStageCompletedFile after this. |
| oobe_config_->WriteFile(kFirstStageCompletedFile, ""); |
| // If all succeeded, we reboot. |
| if (base::PathExists(kFirstStageCompletedFile) && power_manager_proxy_) { |
| if (!skip_reboot_for_testing_) { |
| LOG(INFO) << "Rebooting device."; |
| brillo::ErrorPtr error; |
| if (!power_manager_proxy_->RequestRestart( |
| ::power_manager::REQUEST_RESTART_OTHER, |
| "oobe_config: reboot after rollback restore first stage", |
| &error)) { |
| LOG(ERROR) << "Failed to reboot device, error: " |
| << error->GetMessage(); |
| metrics_.RecordRestoreResult( |
| Metrics::OobeRestoreResult::kStage1Failure); |
| } |
| } else { |
| LOG(INFO) << "Skipping reboot for testing"; |
| } |
| } |
| exit(0); |
| } |
| |
| if (oobe_config_->CheckThirdStage()) { |
| LOG(INFO) << "Starting rollback restore stage 3."; |
| |
| // We load the proto from kEncryptedStatefulRollbackDataPath. |
| string rollback_data_str; |
| if (!oobe_config_->ReadFile(kEncryptedStatefulRollbackDataPath, |
| &rollback_data_str)) { |
| metrics_.RecordRestoreResult(Metrics::OobeRestoreResult::kStage3Failure); |
| return false; |
| } |
| RollbackData rollback_data; |
| if (!rollback_data.ParseFromString(rollback_data_str)) { |
| LOG(ERROR) << "Couldn't parse proto."; |
| metrics_.RecordRestoreResult(Metrics::OobeRestoreResult::kStage3Failure); |
| return false; |
| } |
| // We get the data for Chrome and assemble the config. |
| if (!AssembleConfig(rollback_data, config)) { |
| LOG(ERROR) << "Failed to assemble config."; |
| metrics_.RecordRestoreResult(Metrics::OobeRestoreResult::kStage3Failure); |
| return false; |
| } |
| |
| // If it succeeded, we remove all files from |
| // kEncryptedStatefulRollbackDataPath. |
| LOG(INFO) << "Cleaning up rollback data."; |
| oobe_config_->CleanupEncryptedStatefulDirectory(); |
| |
| LOG(INFO) << "Rollback restore completed successfully."; |
| metrics_.RecordRestoreResult(Metrics::OobeRestoreResult::kSuccess); |
| return true; |
| } |
| |
| NOTREACHED(); |
| return false; |
| } |
| |
| bool LoadOobeConfigRollback::AssembleConfig(const RollbackData& rollback_data, |
| string* config) { |
| // Possible values are defined in |
| // chrome/browser/resources/chromeos/login/oobe_types.js. |
| // TODO(zentaro): Export these strings as constants. |
| base::DictionaryValue dictionary; |
| // Always skip next screen. |
| dictionary.SetBoolean("welcomeNext", true); |
| // Always skip network selection screen if possible. |
| dictionary.SetBoolean("networkUseConnected", true); |
| // We don't want updates after rolling back. |
| dictionary.SetBoolean("updateSkipNonCritical", true); |
| // Set whether metrics should be enabled if it exists in |rollback_data|. |
| dictionary.SetBoolean("eulaSendStatistics", |
| rollback_data.eula_send_statistics()); |
| // Set whether the EULA as already accepted and can be skipped if the field is |
| // present in |rollback_data|. |
| dictionary.SetBoolean("eulaAutoAccept", rollback_data.eula_auto_accept()); |
| // Tell Chrome that it still has to create some robot accounts that were |
| // destroyed during rollback. |
| dictionary.SetBoolean("enrollmentRestoreAfterRollback", true); |
| |
| return base::JSONWriter::Write(dictionary, config); |
| } |
| |
| } // namespace oobe_config |