PolicyManager: Add a random number provider.

This patch adds a new provider with a single variable that returns a
random value from /dev/urandom every time it is called. The variable
is exported to all the policy implementations (currently none) in the
policy_manager/all_variables.h file.

BUG=None
TEST=unittests.

Change-Id: I6efdecd0f37f1a706b5a0dfd3a77ac4205e35aa0
Reviewed-on: https://chromium-review.googlesource.com/181537
Reviewed-by: Gilad Arnold <garnold@chromium.org>
Commit-Queue: Alex Deymo <deymo@chromium.org>
Tested-by: Alex Deymo <deymo@chromium.org>
diff --git a/policy_manager/all_variables.h b/policy_manager/all_variables.h
index e1982f2..be77698 100644
--- a/policy_manager/all_variables.h
+++ b/policy_manager/all_variables.h
@@ -13,4 +13,6 @@
 // This file includes all the different provider's header files with these
 // definitions.
 
+#include "policy_manager/random_vars.h"
+
 #endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_POLICY_MANAGER_ALL_VARIABLES_H
diff --git a/policy_manager/random_provider.cc b/policy_manager/random_provider.cc
new file mode 100644
index 0000000..f2373b0
--- /dev/null
+++ b/policy_manager/random_provider.cc
@@ -0,0 +1,84 @@
+// Copyright (c) 2014 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 <stdio.h>
+#include <unistd.h>
+
+#include <base/file_path.h>
+#include <base/file_util.h>
+
+#include "policy_manager/random_provider.h"
+#include "policy_manager/random_vars.h"
+
+using std::string;
+
+namespace {
+
+// The device providing randomness.
+const char* kRandomDevice = "/dev/urandom";
+
+}  // namespace
+
+namespace chromeos_policy_manager {
+
+// The random variable class implementation.
+class RandomVariable : public Variable<uint64> {
+ public:
+  RandomVariable(FILE* fp) : fp_(fp) {}
+  virtual ~RandomVariable() {}
+
+ protected:
+  virtual const uint64* GetValue(base::TimeDelta /* timeout */,
+                                 string* errmsg) {
+    uint8 buf[sizeof(uint64)];
+    unsigned int buf_rd = 0;
+
+    while (buf_rd < sizeof(uint64)) {
+      int rd = fread(buf + buf_rd, 1, sizeof(uint64) - buf_rd, fp_.get());
+      if (rd == 0 || ferror(fp_.get())) {
+        // Either EOF on fp or read failed.
+        if (errmsg)
+          *errmsg = string("Error reading from the random device: ")
+              + kRandomDevice;
+        return NULL;
+      }
+      buf_rd += rd;
+    }
+    // Convert the result to a uint64.
+    uint64 result = 0;
+    for (unsigned int i = 0; i < sizeof(uint64); ++i)
+      result = (result << 8) | buf[i];
+
+    return new uint64(result);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(RandomVariable);
+
+  file_util::ScopedFILE fp_;
+};
+
+
+// RandomProvider implementation.
+
+bool RandomProvider::Init(void) {
+  // Check for double Init()
+  if (var_random_seed != NULL)
+    return false;
+
+  FILE* fp = fopen(kRandomDevice, "r");
+  if (!fp)
+    return false;
+  var_random_seed = new RandomVariable(fp);
+  return true;
+}
+
+void RandomProvider::Finalize(void) {
+  if (var_random_seed) {
+    delete var_random_seed;
+    var_random_seed = NULL;
+  }
+}
+
+}  // namespace chromeos_policy_manager
diff --git a/policy_manager/random_provider.h b/policy_manager/random_provider.h
new file mode 100644
index 0000000..7c7bae9
--- /dev/null
+++ b/policy_manager/random_provider.h
@@ -0,0 +1,30 @@
+// Copyright (c) 2014 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 CHROMEOS_PLATFORM_UPDATE_ENGINE_PM_RANDOM_PROVIDER_H
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_PM_RANDOM_PROVIDER_H
+
+#include "base/basictypes.h"
+
+namespace chromeos_policy_manager {
+
+// Provider of random values.
+class RandomProvider {
+ public:
+  RandomProvider() {}
+
+  // Initialize the provider variables and internal state. Returns whether it
+  // succeeded.
+  bool Init();
+
+  // Destroy all the provider variables in a best-effor approach.
+  void Finalize();
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(RandomProvider);
+};
+
+}  // namespace chromeos_policy_manager
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_PM_RANDOM_PROVIDER_H
diff --git a/policy_manager/random_provider_unittest.cc b/policy_manager/random_provider_unittest.cc
new file mode 100644
index 0000000..82ee5cc
--- /dev/null
+++ b/policy_manager/random_provider_unittest.cc
@@ -0,0 +1,57 @@
+// Copyright (c) 2014 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 <base/memory/scoped_ptr.h>
+#include <gtest/gtest.h>
+#include <string>
+
+#include "policy_manager/random_provider.h"
+#include "policy_manager/random_vars.h"
+
+using base::TimeDelta;
+using std::string;
+
+namespace chromeos_policy_manager {
+
+class PMRandomProviderTest : public ::testing::Test {
+ protected:
+  virtual void SetUp() {
+    ASSERT_TRUE(var_random_seed == NULL);
+    EXPECT_TRUE(provider_.Init());
+  }
+
+  virtual void TearDown() {
+    provider_.Finalize();
+    ASSERT_TRUE(var_random_seed == NULL);
+  }
+
+ private:
+  RandomProvider provider_;
+};
+
+TEST_F(PMRandomProviderTest, InitFinalize) {
+  // The provider should initialize the variable with a valid object.
+  ASSERT_TRUE(var_random_seed != NULL);
+}
+
+TEST_F(PMRandomProviderTest, GetRandomValues) {
+  string errmsg;
+  scoped_ptr<const uint64> value(
+      var_random_seed->GetValue(TimeDelta::FromSeconds(1.), &errmsg));
+  ASSERT_TRUE(value != NULL);
+
+  bool returns_allways_the_same_value = true;
+  // Test that at least the returned values are different. This test fails,
+  // by design, once every 2^320 runs.
+  for (int i = 0; i < 5; i++) {
+    scoped_ptr<const uint64> other_value(
+        var_random_seed->GetValue(TimeDelta::FromSeconds(1.), &errmsg));
+    ASSERT_TRUE(other_value != NULL);
+    returns_allways_the_same_value = returns_allways_the_same_value &&
+        *other_value == *value;
+  }
+  EXPECT_FALSE(returns_allways_the_same_value);
+}
+
+}  // namespace chromeos_policy_manager
diff --git a/policy_manager/random_vars.cc b/policy_manager/random_vars.cc
new file mode 100644
index 0000000..1eb0c0a
--- /dev/null
+++ b/policy_manager/random_vars.cc
@@ -0,0 +1,11 @@
+// Copyright (c) 2014 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 "policy_manager/random_vars.h"
+
+namespace chromeos_policy_manager {
+
+Variable<uint64>* var_random_seed = NULL;
+
+}  // namespace chromeos_policy_manager
diff --git a/policy_manager/random_vars.h b/policy_manager/random_vars.h
new file mode 100644
index 0000000..c1563c5
--- /dev/null
+++ b/policy_manager/random_vars.h
@@ -0,0 +1,21 @@
+// Copyright (c) 2014 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 CHROMEOS_PLATFORM_UPDATE_ENGINE_PM_RANDOM_VARS_H
+#define CHROMEOS_PLATFORM_UPDATE_ENGINE_PM_RANDOM_VARS_H
+
+#include "base/basictypes.h"
+#include "policy_manager/variable.h"
+
+namespace chromeos_policy_manager {
+
+// Return a random number every time it is requested. Note that values returned
+// by the variables are cached by the EvaluationContext, so the returned value
+// will be the same during the same policy request. If more random values are
+// needed use a PRNG seeded with this value.
+extern Variable<uint64>* var_random_seed;
+
+}  // namespace chromeos_policy_manager
+
+#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_PM_RANDOM_VARS_H
diff --git a/policy_manager/variable.h b/policy_manager/variable.h
index 46defbc..6acd31f 100644
--- a/policy_manager/variable.h
+++ b/policy_manager/variable.h
@@ -8,6 +8,7 @@
 #include <string>
 
 #include <base/time.h>
+#include <gtest/gtest_prod.h>  // for FRIEND_TEST
 
 namespace chromeos_policy_manager {
 
@@ -18,6 +19,9 @@
   virtual ~Variable() {}
 
  protected:
+  friend class PMRandomProviderTest;
+  FRIEND_TEST(PMRandomProviderTest, GetRandomValues);
+
   // Gets the current value of the variable. The current value is copied to a
   // new object and returned. The caller of this method owns the object and
   // should delete it.