login: Check TPM firmware update device policy

For enterprise-managed devices, TPM firmware updates require
permission by the administrator. Allow the update to be started if the
respective device policy is in place.

BUG=chromium:762030
TEST=unit test

Reviewed-on: https://chromium-review.googlesource.com/679655
Commit-Ready: Mattias Nissler <mnissler@chromium.org>
Tested-by: Mattias Nissler <mnissler@chromium.org>
Reviewed-by: Dan Erat <derat@chromium.org>

Change-Id: Icbbf43b18420be60303f919182369c63f0600674
Reviewed-on: https://chromium-review.googlesource.com/700674
Reviewed-by: Mattias Nissler <mnissler@chromium.org>
Tested-by: Mattias Nissler <mnissler@chromium.org>
diff --git a/login_manager/mock_device_policy_service.h b/login_manager/mock_device_policy_service.h
index 20bfa7f..1f70fe5 100644
--- a/login_manager/mock_device_policy_service.h
+++ b/login_manager/mock_device_policy_service.h
@@ -46,9 +46,6 @@
 
   void set_crossystem(Crossystem* crossystem) { crossystem_ = crossystem; }
   void set_vpd_process(VpdProcess* vpd_process) { vpd_process_ = vpd_process; }
-
- private:
-  enterprise_management::ChromeDeviceSettingsProto proto_;
 };
 }  // namespace login_manager
 
diff --git a/login_manager/session_manager_impl.cc b/login_manager/session_manager_impl.cc
index 3344f83..c60a2ca 100644
--- a/login_manager/session_manager_impl.cc
+++ b/login_manager/session_manager_impl.cc
@@ -883,11 +883,14 @@
   // For remotely managed devices, make sure the requested update mode matches
   // the admin-configured one in device policy.
   if (device_policy_->InstallAttributesEnterpriseMode()) {
-    // TODO(mnissler): Verify that device policy matches |update_mode|.
-    auto error = CreateError(dbus_error::kNotAvailable,
-                             "Not yet supported on enterprise devices.");
-    response->ReplyWithError(error.get());
-    return;
+    const enterprise_management::TPMFirmwareUpdateSettingsProto& settings =
+        device_policy_->GetSettings().tpm_firmware_update_settings();
+    if (!settings.allow_user_initiated_powerwash()) {
+      auto error = CreateError(dbus_error::kNotAvailable,
+                               "Policy doesn't allow TPM firmware update.");
+      response->ReplyWithError(error.get());
+      return;
+    }
   }
 
   // Check whether a firmware update is present.
diff --git a/login_manager/session_manager_impl_unittest.cc b/login_manager/session_manager_impl_unittest.cc
index 0abf67f..f3db6af 100644
--- a/login_manager/session_manager_impl_unittest.cc
+++ b/login_manager/session_manager_impl_unittest.cc
@@ -82,6 +82,7 @@
 using ::testing::Mock;
 using ::testing::NotNull;
 using ::testing::Return;
+using ::testing::ReturnRef;
 using ::testing::SaveArg;
 using ::testing::SetArgumentPointee;
 using ::testing::StartsWith;
@@ -95,6 +96,8 @@
 using brillo::cryptohome::home::kGuestUserName;
 
 using enterprise_management::ChromeDeviceSettingsProto;
+using enterprise_management::PolicyData;
+using enterprise_management::PolicyFetchResponse;
 
 using std::map;
 using std::string;
@@ -347,7 +350,9 @@
         system_clock_proxy_.get());
     impl_->SetSystemClockLastSyncInfoRetryDelayForTesting(base::TimeDelta());
 
-    device_policy_service_ = new MockDevicePolicyService();
+    device_policy_store_ = new MockPolicyStore();
+    device_policy_service_ = new MockDevicePolicyService(
+        std::unique_ptr<MockPolicyStore>(device_policy_store_), &owner_key_);
     user_policy_service_factory_ =
         new testing::NiceMock<MockUserPolicyServiceFactory>();
     ON_CALL(*user_policy_service_factory_, Create(_))
@@ -553,6 +558,7 @@
   // on them after we hand them off.
   // Owned by SessionManagerImpl.
   MockInitDaemonController* init_controller_ = nullptr;
+  MockPolicyStore* device_policy_store_ = nullptr;
   MockDevicePolicyService* device_policy_service_ = nullptr;
   MockUserPolicyServiceFactory* user_policy_service_factory_ = nullptr;
   map<string, MockPolicyService*> user_policy_services_;
@@ -2173,6 +2179,8 @@
     ON_CALL(vpd_process_, RunInBackground(_, _, _))
         .WillByDefault(
             Invoke(this, &StartTPMFirmwareUpdateTest::RunVpdProcess));
+    ON_CALL(*device_policy_store_, Get())
+        .WillByDefault(ReturnRef(policy_));
 
     SetFileExists(SessionManagerImpl::kTPMFirmwareUpdateAvailableFile, true);
   }
@@ -2248,6 +2256,12 @@
     vpd_status_ = status;
   }
 
+  void SetPolicy(const ChromeDeviceSettingsProto& settings) {
+    PolicyData policy_data;
+    CHECK(settings.SerializeToString(policy_data.mutable_policy_value()));
+    CHECK(policy_data.SerializeToString(policy_.mutable_policy_data()));
+  }
+
   std::string update_mode_ = "first_boot";
   std::string existing_vpd_params_;
   std::string expected_vpd_params_ = "mode:first_boot";
@@ -2256,6 +2270,7 @@
   bool vpd_spawned_ = true;
   bool vpd_status_ = true;
   VpdProcess::CompletionCallback completion_;
+  PolicyFetchResponse policy_;
 };
 
 TEST_F(StartTPMFirmwareUpdateTest, Success_FirstBoot) {
@@ -2283,12 +2298,22 @@
   ExpectError(dbus_error::kInvalidParameter);
 }
 
-TEST_F(StartTPMFirmwareUpdateTest, Enterprise) {
+TEST_F(StartTPMFirmwareUpdateTest, EnterpriseNotSet) {
   EXPECT_CALL(*device_policy_service_, InstallAttributesEnterpriseMode())
       .WillRepeatedly(Return(true));
   ExpectError(dbus_error::kNotAvailable);
 }
 
+TEST_F(StartTPMFirmwareUpdateTest, EnterpriseAllowed) {
+  EXPECT_CALL(*device_policy_service_, InstallAttributesEnterpriseMode())
+      .WillRepeatedly(Return(true));
+  ChromeDeviceSettingsProto settings;
+  settings.mutable_tpm_firmware_update_settings()
+      ->set_allow_user_initiated_powerwash(true);
+  SetPolicy(settings);
+  ExpectDeviceRestart();
+}
+
 TEST_F(StartTPMFirmwareUpdateTest, VpdSpawnError) {
   SetVpdSpawned(false);
   ExpectError(dbus_error::kVpdUpdateFailed);