aboutsummaryrefslogtreecommitdiffstats
path: root/install_attributes
diff options
context:
space:
mode:
Diffstat (limited to 'install_attributes')
-rw-r--r--install_attributes/libinstallattributes.cc82
-rw-r--r--install_attributes/libinstallattributes.h66
-rw-r--r--install_attributes/mock_install_attributes_reader.cc22
-rw-r--r--install_attributes/mock_install_attributes_reader.h19
-rw-r--r--install_attributes/tests/consumer.pb1
-rw-r--r--install_attributes/tests/corrupt.pb0
-rw-r--r--install_attributes/tests/libinstallattributes_unittest.cc83
-rw-r--r--install_attributes/tests/managed.pbbin0 -> 211 bytes
8 files changed, 273 insertions, 0 deletions
diff --git a/install_attributes/libinstallattributes.cc b/install_attributes/libinstallattributes.cc
new file mode 100644
index 0000000..52f9f70
--- /dev/null
+++ b/install_attributes/libinstallattributes.cc
@@ -0,0 +1,82 @@
+// Copyright 2016 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 "libinstallattributes.h"
+
+#include <base/files/file_util.h>
+#include <base/logging.h>
+
+#include "bindings/install_attributes.pb.h"
+
+namespace {
+
+// Written by cryptohome or by lockbox-cache after signature verification and
+// thus guaranteed to be unadulterated.
+const char kInstallAttributesPath[] = "/run/lockbox/install_attributes.pb";
+
+} // namespace
+
+// The source of truth for these constants is Chromium
+// //chrome/browser/chromeos/settings/install_attributes.cc.
+const char InstallAttributesReader::kAttrMode[] = "enterprise.mode";
+const char InstallAttributesReader::kDeviceModeConsumer[] = "consumer";
+const char InstallAttributesReader::kDeviceModeEnterprise[] = "enterprise";
+const char InstallAttributesReader::kDeviceModeEnterpriseAD[] = "enterprise_ad";
+const char InstallAttributesReader::kDeviceModeLegacyRetail[] = "kiosk";
+const char InstallAttributesReader::kDeviceModeConsumerKiosk[] =
+ "consumer_kiosk";
+
+InstallAttributesReader::InstallAttributesReader()
+ : install_attributes_path_(kInstallAttributesPath) {
+}
+
+InstallAttributesReader::~InstallAttributesReader() {
+}
+
+const std::string& InstallAttributesReader::GetAttribute(
+ const std::string& key) {
+ // By its very nature of immutable attributes, once read successfully the
+ // attributes can never change and thus never need reloading.
+ if (!initialized_) {
+ TryToLoad();
+ }
+
+ const auto entry = attributes_.find(key);
+ if (entry == attributes_.end()) {
+ return empty_string_;
+ }
+ return entry->second;
+}
+
+bool InstallAttributesReader::IsLocked() {
+ if (!initialized_) {
+ TryToLoad();
+ }
+ return initialized_;
+}
+
+void InstallAttributesReader::TryToLoad() {
+ std::string contents;
+ if (!base::ReadFileToString(install_attributes_path_, &contents)) {
+ // May fail during OOBE or early in the boot process.
+ return;
+ }
+
+ // Parse errors are unrecoverable (lockbox does atomic write), thus mark as
+ // inititialized already before checking for parse errors.
+ initialized_ = true;
+
+ cryptohome::SerializedInstallAttributes install_attributes;
+ if (!install_attributes.ParseFromString(contents)) {
+ LOG(ERROR) << "Can't parse install attributes.";
+ return;
+ }
+
+ for (int i = 0; i < install_attributes.attributes_size(); ++i) {
+ const cryptohome::SerializedInstallAttributes_Attribute& attribute =
+ install_attributes.attributes(i);
+ // Cast value to C string and back to remove trailing zero.
+ attributes_[attribute.name()] = std::string(attribute.value().c_str());
+ }
+}
diff --git a/install_attributes/libinstallattributes.h b/install_attributes/libinstallattributes.h
new file mode 100644
index 0000000..b947156
--- /dev/null
+++ b/install_attributes/libinstallattributes.h
@@ -0,0 +1,66 @@
+// Copyright 2016 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.
+
+#ifndef LIBBRILLO_INSTALL_ATTRIBUTES_LIBINSTALLATTRIBUTES_H_
+#define LIBBRILLO_INSTALL_ATTRIBUTES_LIBINSTALLATTRIBUTES_H_
+
+#include <map>
+#include <string>
+
+#include <base/files/file_path.h>
+#include <brillo/brillo_export.h>
+
+// Simple caching reader for the (verified) install attributes, a TPM-backed
+// write once read many store. Install attributes may be written exactly once
+// by a single, atomic write-and-lock operation encompassing zero or more
+// attributes. Once locked, install attributes cannot be re-written unless TPM
+// is reset (eg. by powerwashing the device).
+class BRILLO_EXPORT InstallAttributesReader {
+ public:
+ static const char kAttrMode[];
+
+ // Constants for the possible device modes.
+ static const char kDeviceModeConsumer[];
+ static const char kDeviceModeEnterprise[];
+ static const char kDeviceModeEnterpriseAD[];
+ static const char kDeviceModeLegacyRetail[];
+ static const char kDeviceModeConsumerKiosk[];
+
+ InstallAttributesReader();
+ virtual ~InstallAttributesReader();
+
+ // Try to load install attributes (unless cached already) and return the
+ // attribute for |key| or an empty string in case |key| doesn't exist or in
+ // case install attributes couldn't (yet) be loaded. The latter is expected
+ // during OOBE (install attributes haven't yet been finalized) or early in the
+ // boot sequence (install attributes haven't yet been verified).
+ const std::string& GetAttribute(const std::string& key);
+
+ // Try to load install attributes (unless cached already) and return whether
+ // they have yet been written-and-locked.
+ bool IsLocked();
+
+ protected:
+ // Attributes cache.
+ std::map<std::string, std::string> attributes_;
+
+ // Path to the *verified* install attributes file on disk.
+ base::FilePath install_attributes_path_;
+
+ // Whether install attributes have been read successfully. Reading a file
+ // containing an empty attributes proto indicates consumer mode and counts as
+ // successful, too.
+ bool initialized_ = false;
+
+private:
+ // Try to load the verified install attributes from disk. This is expected to
+ // fail when install attributes haven't yet been finalized (OOBE) or verified
+ // (early in the boot sequence).
+ void TryToLoad();
+
+ // Empty string to return on error.
+ std::string empty_string_;
+};
+
+#endif // LIBBRILLO_LIBINSTALLATTRIBUTES_H_
diff --git a/install_attributes/mock_install_attributes_reader.cc b/install_attributes/mock_install_attributes_reader.cc
new file mode 100644
index 0000000..da18988
--- /dev/null
+++ b/install_attributes/mock_install_attributes_reader.cc
@@ -0,0 +1,22 @@
+// Copyright 2016 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 "mock_install_attributes_reader.h"
+
+MockInstallAttributesReader::MockInstallAttributesReader(
+ const cryptohome::SerializedInstallAttributes& install_attributes) {
+ for (int i = 0; i < install_attributes.attributes_size(); ++i) {
+ const cryptohome::SerializedInstallAttributes_Attribute& attribute =
+ install_attributes.attributes(i);
+ // Cast value to C string and back to remove trailing zero.
+ attributes_[attribute.name()] = std::string(attribute.value().c_str());
+ }
+ initialized_ = true;
+}
+
+MockInstallAttributesReader::MockInstallAttributesReader(
+ const std::string& device_mode, bool initialized) {
+ attributes_[kAttrMode] = device_mode;
+ initialized_ = initialized;
+}
diff --git a/install_attributes/mock_install_attributes_reader.h b/install_attributes/mock_install_attributes_reader.h
new file mode 100644
index 0000000..5ccee02
--- /dev/null
+++ b/install_attributes/mock_install_attributes_reader.h
@@ -0,0 +1,19 @@
+// Copyright 2016 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.
+
+#ifndef LIBBRILLO_INSTALL_ATTRIBUTES_MOCK_INSTALL_ATTRIBUTES_READER_H_
+#define LIBBRILLO_INSTALL_ATTRIBUTES_MOCK_INSTALL_ATTRIBUTES_READER_H_
+
+#include "libinstallattributes.h"
+
+#include "bindings/install_attributes.pb.h"
+
+class MockInstallAttributesReader : public InstallAttributesReader {
+ public:
+ explicit MockInstallAttributesReader(
+ const cryptohome::SerializedInstallAttributes& install_attributes);
+ MockInstallAttributesReader(const std::string& device_mode, bool initialized);
+};
+
+#endif // LIBBRILLO_INSTALL_ATTRIBUTES_MOCK_INSTALL_ATTRIBUTES_READER_H_
diff --git a/install_attributes/tests/consumer.pb b/install_attributes/tests/consumer.pb
new file mode 100644
index 0000000..e19a122
--- /dev/null
+++ b/install_attributes/tests/consumer.pb
@@ -0,0 +1 @@
+ \ No newline at end of file
diff --git a/install_attributes/tests/corrupt.pb b/install_attributes/tests/corrupt.pb
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/install_attributes/tests/corrupt.pb
diff --git a/install_attributes/tests/libinstallattributes_unittest.cc b/install_attributes/tests/libinstallattributes_unittest.cc
new file mode 100644
index 0000000..45ff827
--- /dev/null
+++ b/install_attributes/tests/libinstallattributes_unittest.cc
@@ -0,0 +1,83 @@
+// Copyright (c) 2012 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 "install_attributes/libinstallattributes.h"
+
+#include <string>
+
+#include <gtest/gtest.h>
+
+// Allows to override the install attributes path while preserving all the
+// functionality of the original class.
+class MockInstallAttributesReader : public InstallAttributesReader {
+ public:
+ void SetPath(const std::string& filename) {
+ install_attributes_path_ = base::FilePath(filename);
+ }
+ size_t GetAttributesCount() const { return attributes_.size(); }
+};
+
+TEST(InstallAttributesTest, ReadNonexistingAttributes) {
+ MockInstallAttributesReader reader;
+ reader.SetPath("non-existing.pb");
+ ASSERT_FALSE(reader.IsLocked());
+ ASSERT_EQ(0, reader.GetAttributesCount());
+}
+
+// corrupt.pb is an invalid proto.
+TEST(InstallAttributesTest, ReadCorruptAttributes) {
+ MockInstallAttributesReader reader;
+ reader.SetPath("install_attributes/tests/corrupt.pb");
+ ASSERT_TRUE(reader.IsLocked());
+ ASSERT_EQ(0, reader.GetAttributesCount());
+}
+
+// consumer.pb is a valid proto containing no attributes.
+TEST(InstallAttributesTest, ReadEmptyAttributes) {
+ MockInstallAttributesReader reader;
+ reader.SetPath("install_attributes/tests/consumer.pb");
+ ASSERT_TRUE(reader.IsLocked());
+ ASSERT_EQ(0, reader.GetAttributesCount());
+}
+
+// managed.pb is a valid proto containing the usual enterprise enrollment
+// attributes.
+TEST(InstallAttributesTest, ReadManagedAttributes) {
+ MockInstallAttributesReader reader;
+ reader.SetPath("install_attributes/tests/managed.pb");
+ ASSERT_TRUE(reader.IsLocked());
+ ASSERT_EQ(std::string(), reader.GetAttribute("non-existing"));
+ ASSERT_EQ("enterprise", reader.GetAttribute("enterprise.mode"));
+}
+
+// Going from non-existing attributes file to existing attributes file must
+// work, i.e. the non-existence of the attributes file must not be cached.
+TEST(InstallAttributesTest, ProgressionFromNonExistingToManaged) {
+ MockInstallAttributesReader reader;
+ reader.SetPath("non-existing.pb");
+ ASSERT_FALSE(reader.IsLocked());
+ ASSERT_EQ(0, reader.GetAttributesCount());
+
+ reader.SetPath("install_attributes/tests/managed.pb");
+ ASSERT_TRUE(reader.IsLocked());
+ ASSERT_EQ("enterprise", reader.GetAttribute("enterprise.mode"));
+}
+
+// Going from empty attributes file to non-empty attributes file must not work,
+// i.e. the non-existence of the attributes must be cached.
+TEST(InstallAttributesTest, NoProgressionFromEmptyToManaged) {
+ MockInstallAttributesReader reader;
+ reader.SetPath("install_attributes/tests/consumer.pb");
+ ASSERT_TRUE(reader.IsLocked());
+ ASSERT_EQ(0, reader.GetAttributesCount());
+
+ reader.SetPath("install_attributes/tests/managed.pb");
+ ASSERT_TRUE(reader.IsLocked());
+ ASSERT_EQ(std::string(), reader.GetAttribute("enterprise.mode"));
+}
+
+int main(int argc, char* argv[]) {
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/install_attributes/tests/managed.pb b/install_attributes/tests/managed.pb
new file mode 100644
index 0000000..4060a49
--- /dev/null
+++ b/install_attributes/tests/managed.pb
Binary files differ