Wire up server-backed state key generation DBus API.
This implements a DBus call to generate server-backed state keys. This
is intended for Chrome to call when it needs state keys for
communicating with the device management server.
BUG=chromium:358213
TEST=None
Change-Id: I8fdfba3f25e032d1942a74a835077814c31305a2
Reviewed-on: https://chromium-review.googlesource.com/194313
Tested-by: Mattias Nissler <mnissler@chromium.org>
Reviewed-by: Richard Barnette <jrbarnette@chromium.org>
Reviewed-by: Chris Masone <cmasone@chromium.org>
Commit-Queue: Mattias Nissler <mnissler@chromium.org>
diff --git a/SessionManager.conf b/SessionManager.conf
index 938b50d..f09cd37 100644
--- a/SessionManager.conf
+++ b/SessionManager.conf
@@ -9,6 +9,11 @@
<policy user="root">
<allow own="org.chromium.SessionManager" />
<allow send_destination="org.chromium.SessionManager" />
+
+ <!-- Only root should be allowed to call InitMachineInfo. -->
+ <allow send_destination="org.chromium.SessionManager"
+ send_interface="org.chromium.SessionManagerInterface"
+ send_member="InitMachineInfo"/>
</policy>
<policy user="chronos">
@@ -72,6 +77,9 @@
<allow send_destination="org.chromium.SessionManager"
send_interface="org.chromium.SessionManagerInterface"
send_member="SetFlagsForUser"/>
+ <allow send_destination="org.chromium.SessionManager"
+ send_interface="org.chromium.SessionManagerInterface"
+ send_member="GetServerBackedStateKeys"/>
</policy>
<policy user="power">
diff --git a/dbus_error_types.h b/dbus_error_types.h
index e219b38..e17c28a 100644
--- a/dbus_error_types.h
+++ b/dbus_error_types.h
@@ -10,6 +10,7 @@
#define INTERFACE "org.chromium.SessionManagerInterface"
static const char kEmitFailed[] = INTERFACE ".EmitFailed";
+static const char kInitMachineInfoFail[] = INTERFACE ".InitMachineInfoFail";
static const char kInvalidAccount[] = INTERFACE ".InvalidAccount";
static const char kNoOwnerKey[] = INTERFACE ".NoOwnerKey";
static const char kNoUserNssDb[] = INTERFACE ".NoUserNssDb";
@@ -17,8 +18,8 @@
static const char kPubkeySetIllegal[] = INTERFACE ".PubkeySetIllegal";
static const char kSessionDoesNotExist[] = INTERFACE ".SessionDoesNotExist";
static const char kSessionExists[] = INTERFACE ".SessionExists";
-static const char kSigEncodeFail[] = INTERFACE ".SigEncodeFail";
static const char kSigDecodeFail[] = INTERFACE ".SigDecodeFail";
+static const char kSigEncodeFail[] = INTERFACE ".SigEncodeFail";
static const char kTestingChannelError[] = INTERFACE ".TestingChannelError";
static const char kUnknownPid[] = INTERFACE ".UnknownPid";
static const char kVerifyFail[] = INTERFACE ".VerifyFail";
diff --git a/init/ui-collect-machine-info.conf b/init/ui-collect-machine-info.conf
new file mode 100644
index 0000000..c283a6d
--- /dev/null
+++ b/init/ui-collect-machine-info.conf
@@ -0,0 +1,37 @@
+# Copyright 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.
+
+description "Collect machine information for session_manager"
+author "chromium-os-dev@chromium.org"
+
+# This job collects machine information and places it in a file. It is
+# then pushed to session_manager by ui-init-late.
+
+# Start after the system is mostly up and running, which also implies
+# that the VPD has been read and the udev database is fully initialized.
+start on started system-services
+
+env UI_MACHINE_INFO_FILE=/var/run/session_manager/machine-info
+
+script
+ (
+ # Just continue if one of the commands below fails.
+ set +e
+
+ # Grab full VPD data from dump_vpd_log, which contains the machine
+ # serial number and echo group code.
+ #
+ # TODO(mnissler): As things stand, dump_vpd_log prints error
+ # messages on stdout in some situations, so only emit its output on
+ # clean termination. Simplify this after http://crbug.com/369188 is
+ # fixed.
+ VPD_DATA=$(dump_vpd_log --full --stdout)
+ [ $? -eq 0 ] && echo "${VPD_DATA}"
+
+ # Grab the disk serial number from the udev database.
+ ROOTDEV=$(rootdev -s -d || true)
+ udevadm info --query=property --name="${ROOTDEV}" |
+ awk -F = '/^ID_SERIAL=/ { print "root_disk_serial_number=" $2 }'
+ ) > "${UI_MACHINE_INFO_FILE}"
+end script
diff --git a/init/ui-init-late.conf b/init/ui-init-late.conf
new file mode 100644
index 0000000..90c5e77
--- /dev/null
+++ b/init/ui-init-late.conf
@@ -0,0 +1,30 @@
+# Copyright 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.
+
+description "Supplemental session_manager initialization after boot"
+author "chromium-os-dev@chromium.org"
+
+# This job forwards machine information to session_manager over DBus.
+# The data is used by session_manager eventually, but is not critical to
+# starting the UI.
+
+# Machine information needs to be pushed to session_manager every time
+# it starts. However, the data may not be available yet. In that case
+# this job runs again after ui-collect-machine-info has collected the
+# data.
+start on login-prompt-visible or stopped ui-collect-machine-info
+
+env UI_MACHINE_INFO_FILE=/var/run/session_manager/machine-info
+
+script
+ # Bail out if data collection is still pending.
+ [ -e "${UI_MACHINE_INFO_FILE}" ] || exit 0
+
+ dbus-send --system --dest=org.chromium.SessionManager \
+ --type=method_call /org/chromium/SessionManager \
+ org.chromium.SessionManagerInterface.InitMachineInfo \
+ string:"$(cat "${UI_MACHINE_INFO_FILE}")" ||
+ logger -t "${UPSTART_JOB}" \
+ "Failed to pass machine info to session_manager!"
+end script
diff --git a/org.chromium.SessionManagerInterface.xml b/org.chromium.SessionManagerInterface.xml
index d42e6c3..ec5ce78 100644
--- a/org.chromium.SessionManagerInterface.xml
+++ b/org.chromium.SessionManagerInterface.xml
@@ -306,6 +306,37 @@
<arg type="s" name="user_email" direction="in" />
<arg type="as" name="flags" direction="in" />
</method>
+
+ <!--
+ GetServerBackedStateKeys:
+ @state_keys: The array of currently valid state keys.
+
+ Requests server-backed state keys to be computed and returned. A
+ server-backed state key is an opaque client-determined identifier
+ that's used to stage state in a server to be retrieved after device
+ recovery. These are used to figure out device state such as previous
+ enrollment domain and whether the device got marked as stolen by its
+ owner. The keys are time-dependent, with each key being valid only for
+ a window of time, and this call returns the currently valid state key
+ plus a number of subsequent state keys that span a year of time in
+ coverage.
+ -->
+ <method name="GetServerBackedStateKeys">
+ <arg type="aay" name="state_keys" direction="out" />
+ </method>
+
+ <!--
+ InitMachineInfo:
+ @data: A string containing newline-separated key=value pairs.
+
+ Initializes supplemental machine information for use by session manager
+ that has be asynchronously determined in the boot process after
+ starting session_manager. This method gets invoked by the ui-init-late
+ init job; nothing else should call this method.
+ -->
+ <method name="InitMachineInfo">
+ <arg type="s" name="data" direction="in" />
+ </method>
</interface>
<!-- ********************************************************************* -->
</node>
diff --git a/session_manager_dbus_adaptor.cc b/session_manager_dbus_adaptor.cc
index b944f84..ae13332 100644
--- a/session_manager_dbus_adaptor.cc
+++ b/session_manager_dbus_adaptor.cc
@@ -14,11 +14,12 @@
#include <base/file_util.h>
#include <base/memory/scoped_ptr.h>
#include <base/stl_util.h>
+#include <chromeos/dbus/service_constants.h>
#include <dbus/exported_object.h>
#include <dbus/message.h>
-#include "login_manager/session_manager_impl.h"
#include "login_manager/policy_service.h"
+#include "login_manager/session_manager_impl.h"
namespace login_manager {
namespace {
@@ -103,6 +104,26 @@
}
return response.Pass();
}
+
+// Handles completion of a server-backed state key retrieval operation and
+// passes the response back to the waiting DBus invocation context.
+void HandleGetServerBackedStateKeysCompletion(
+ dbus::MethodCall* call,
+ const dbus::ExportedObject::ResponseSender& sender,
+ const std::vector<std::vector<uint8> >& state_keys) {
+ scoped_ptr<dbus::Response> response(dbus::Response::FromMethodCall(call));
+ dbus::MessageWriter writer(response.get());
+ dbus::MessageWriter array_writer(NULL);
+ writer.OpenArray("ay", &array_writer);
+ for (std::vector<std::vector<uint8> >::const_iterator
+ state_key(state_keys.begin());
+ state_key != state_keys.end(); ++state_key) {
+ array_writer.AppendArrayOfBytes(state_key->data(), state_key->size());
+ }
+ writer.CloseContainer(&array_writer);
+ sender.Run(response.Pass());
+}
+
} // namespace
// PolicyService::Completion implementation that forwards the result to a DBus
@@ -212,6 +233,11 @@
ExportSyncDBusMethod(object, kSessionManagerSetFlagsForUser,
&SessionManagerDBusAdaptor::SetFlagsForUser);
+ ExportAsyncDBusMethod(object, kSessionManagerGetServerBackedStateKeys,
+ &SessionManagerDBusAdaptor::GetServerBackedStateKeys);
+ ExportSyncDBusMethod(object, kSessionManagerInitMachineInfo,
+ &SessionManagerDBusAdaptor::InitMachineInfo);
+
CHECK(object->ExportMethodAndBlock(
kDBusIntrospectableInterface, kDBusIntrospectMethod,
base::Bind(&HandleSynchronousDBusMethodCall,
@@ -440,6 +466,28 @@
return scoped_ptr<dbus::Response>(dbus::Response::FromMethodCall(call));
}
+void SessionManagerDBusAdaptor::GetServerBackedStateKeys(
+ dbus::MethodCall* call,
+ dbus::ExportedObject::ResponseSender sender) {
+ std::vector<std::vector<uint8> > state_keys;
+ impl_->RequestServerBackedStateKeys(
+ base::Bind(&HandleGetServerBackedStateKeysCompletion, call, sender));
+}
+
+scoped_ptr<dbus::Response> SessionManagerDBusAdaptor::InitMachineInfo(
+ dbus::MethodCall* call) {
+ dbus::MessageReader reader(call);
+ std::string data;
+ if (!reader.PopString(&data))
+ return CreateInvalidArgsError(call, call->GetSignature());
+
+ SessionManagerImpl::Error error;
+ impl_->InitMachineInfo(data, &error);
+ if (error.is_set())
+ return CreateError(call, error.name(), error.message());
+ return scoped_ptr<dbus::Response>(dbus::Response::FromMethodCall(call));
+}
+
scoped_ptr<dbus::Response> SessionManagerDBusAdaptor::Introspect(
dbus::MethodCall* call) {
std::string output;
diff --git a/session_manager_dbus_adaptor.h b/session_manager_dbus_adaptor.h
index dfacced..0fa3e8f 100644
--- a/session_manager_dbus_adaptor.h
+++ b/session_manager_dbus_adaptor.h
@@ -71,6 +71,11 @@
scoped_ptr<dbus::Response> StartDeviceWipe(dbus::MethodCall* call);
scoped_ptr<dbus::Response> SetFlagsForUser(dbus::MethodCall* call);
+ // Asynchronous.
+ void GetServerBackedStateKeys(dbus::MethodCall* call,
+ dbus::ExportedObject::ResponseSender sender);
+ scoped_ptr<dbus::Response> InitMachineInfo(dbus::MethodCall* call);
+
scoped_ptr<dbus::Response> Introspect(dbus::MethodCall* call);
private:
diff --git a/session_manager_impl.cc b/session_manager_impl.cc
index d9f4d32..fcc0a02 100644
--- a/session_manager_impl.cc
+++ b/session_manager_impl.cc
@@ -39,9 +39,9 @@
#include "login_manager/user_policy_service_factory.h"
using base::FilePath;
-using chromeos::cryptohome::home::kGuestUserName;
using chromeos::cryptohome::home::GetUserPath;
using chromeos::cryptohome::home::SanitizeUserName;
+using chromeos::cryptohome::home::kGuestUserName;
namespace login_manager { // NOLINT
@@ -119,6 +119,7 @@
base::Closure lock_screen_closure,
base::Closure restart_device_closure,
KeyGenerator* key_gen,
+ ServerBackedStateKeyGenerator* state_key_generator,
ProcessManagerServiceInterface* manager,
LoginMetrics* metrics,
NssUtil* nss,
@@ -131,13 +132,13 @@
restart_device_closure_(restart_device_closure),
dbus_emitter_(dbus_emitter),
key_gen_(key_gen),
+ state_key_generator_(state_key_generator),
manager_(manager),
login_metrics_(metrics),
nss_(nss),
system_(utils),
owner_key_(nss->GetOwnerKeyFilePath(), nss),
- mitigator_(key_gen) {
-}
+ mitigator_(key_gen) {}
SessionManagerImpl::~SessionManagerImpl() {
STLDeleteValues(&user_sessions_);
@@ -524,6 +525,21 @@
manager_->SetFlagsForUser(user_email, session_user_flags);
}
+void SessionManagerImpl::RequestServerBackedStateKeys(
+ const ServerBackedStateKeyGenerator::StateKeyCallback& callback) {
+ state_key_generator_->RequestStateKeys(callback);
+}
+
+void SessionManagerImpl::InitMachineInfo(const std::string& data,
+ Error* error) {
+ std::map<std::string, std::string> params;
+ if (!ServerBackedStateKeyGenerator::ParseMachineInfo(data, ¶ms))
+ error->Set(dbus_error::kInitMachineInfoFail, "Parse failure.");
+
+ if (!state_key_generator_->InitMachineInfo(params))
+ error->Set(dbus_error::kInitMachineInfoFail, "Missing parameters.");
+}
+
void SessionManagerImpl::OnPolicyPersisted(bool success) {
dbus_emitter_->EmitSignalWithSuccessFailure(kPropertyChangeCompleteSignal,
success);
diff --git a/session_manager_impl.h b/session_manager_impl.h
index f5fae68..0ca8056 100644
--- a/session_manager_impl.h
+++ b/session_manager_impl.h
@@ -21,6 +21,7 @@
#include "login_manager/policy_key.h"
#include "login_manager/policy_service.h"
#include "login_manager/regen_mitigator.h"
+#include "login_manager/server_backed_state_key_generator.h"
namespace login_manager {
class DBusSignalEmitterInterface;
@@ -79,6 +80,7 @@
base::Closure lock_screen_closure,
base::Closure restart_device_closure,
KeyGenerator* key_gen,
+ ServerBackedStateKeyGenerator* state_key_generator,
ProcessManagerServiceInterface* manager,
LoginMetrics* metrics,
NssUtil* nss,
@@ -152,6 +154,10 @@
void SetFlagsForUser(const std::string&user_email,
const std::vector<std::string>& session_user_flags);
+ void RequestServerBackedStateKeys(
+ const ServerBackedStateKeyGenerator::StateKeyCallback& callback);
+ void InitMachineInfo(const std::string& data, Error* error);
+
// PolicyService::Delegate implementation:
virtual void OnPolicyPersisted(bool success) OVERRIDE;
virtual void OnKeyPersisted(bool success) OVERRIDE;
@@ -199,6 +205,7 @@
DBusSignalEmitterInterface* dbus_emitter_; // Owned by the caller.
KeyGenerator* key_gen_; // Owned by the caller.
+ ServerBackedStateKeyGenerator* state_key_generator_; // Owned by the caller.
ProcessManagerServiceInterface* manager_; // Owned by the caller.
LoginMetrics* login_metrics_; // Owned by the caller.
NssUtil* nss_; // Owned by the caller.
diff --git a/session_manager_impl_unittest.cc b/session_manager_impl_unittest.cc
index 99da7f5..16a7b29 100644
--- a/session_manager_impl_unittest.cc
+++ b/session_manager_impl_unittest.cc
@@ -16,6 +16,7 @@
#include <base/callback.h>
#include <base/command_line.h>
#include <base/file_util.h>
+#include <base/files/file_path.h>
#include <base/files/scoped_temp_dir.h>
#include <base/memory/ref_counted.h>
#include <base/message_loop/message_loop.h>
@@ -42,6 +43,7 @@
#include "login_manager/mock_process_manager_service.h"
#include "login_manager/mock_system_utils.h"
#include "login_manager/mock_user_policy_service_factory.h"
+#include "login_manager/server_backed_state_key_generator.h"
#include "login_manager/stub_upstart_signal_emitter.h"
using ::testing::AnyNumber;
@@ -57,9 +59,9 @@
using ::testing::StrEq;
using ::testing::_;
-using chromeos::cryptohome::home::kGuestUserName;
using chromeos::cryptohome::home::SanitizeUserName;
using chromeos::cryptohome::home::SetSystemSalt;
+using chromeos::cryptohome::home::kGuestUserName;
using std::map;
using std::string;
@@ -71,6 +73,7 @@
public:
SessionManagerImplTest()
: device_policy_service_(new MockDevicePolicyService),
+ state_key_generator_(&utils_),
impl_(scoped_ptr<UpstartSignalEmitter>(new StubUpstartSignalEmitter),
&dbus_emitter_,
base::Bind(&SessionManagerImplTest::FakeLockScreen,
@@ -78,6 +81,7 @@
base::Bind(&SessionManagerImplTest::FakeRestartDevice,
base::Unretained(this)),
&key_gen_,
+ &state_key_generator_,
&manager_,
&metrics_,
&nss_,
@@ -86,8 +90,7 @@
actual_locks_(0),
expected_locks_(0),
actual_restarts_(0),
- expected_restarts_(0) {
- }
+ expected_restarts_(0) {}
virtual ~SessionManagerImplTest() {}
@@ -190,6 +193,7 @@
MockDBusSignalEmitter dbus_emitter_;
MockKeyGenerator key_gen_;
+ ServerBackedStateKeyGenerator state_key_generator_;
MockProcessManagerService manager_;
MockMetrics metrics_;
MockNssUtil nss_;
diff --git a/session_manager_service.cc b/session_manager_service.cc
index 8fca7fd..ce1ce17 100644
--- a/session_manager_service.cc
+++ b/session_manager_service.cc
@@ -14,8 +14,8 @@
#include <base/bind.h>
#include <base/callback.h>
#include <base/command_line.h>
-#include <base/files/file_path.h>
#include <base/file_util.h>
+#include <base/files/file_path.h>
#include <base/logging.h>
#include <base/memory/scoped_ptr.h>
#include <base/message_loop/message_loop.h>
@@ -50,6 +50,7 @@
namespace login_manager {
namespace {
+
// I need a do-nothing action for SIGALRM, or using alarm() will kill me.
void DoNothing(int signal) {}
@@ -108,6 +109,7 @@
system_(utils),
nss_(NssUtil::Create()),
key_gen_(uid, utils),
+ state_key_generator_(utils),
enable_browser_abort_on_hang_(enable_browser_abort_on_hang),
liveness_checking_interval_(hang_detection_interval),
child_exit_handler_(utils),
@@ -163,6 +165,7 @@
power_manager::kPowerManagerInterface,
power_manager::kRequestRestartMethod),
&key_gen_,
+ &state_key_generator_,
this,
login_metrics_,
nss_.get(),
diff --git a/session_manager_service.h b/session_manager_service.h
index 1f8c4ea..45a1613 100644
--- a/session_manager_service.h
+++ b/session_manager_service.h
@@ -22,6 +22,7 @@
#include "login_manager/key_generator.h"
#include "login_manager/liveness_checker.h"
#include "login_manager/process_manager_service_interface.h"
+#include "login_manager/server_backed_state_key_generator.h"
#include "login_manager/session_manager_interface.h"
#include "login_manager/termination_handler.h"
@@ -232,6 +233,7 @@
scoped_ptr<NssUtil> nss_;
KeyGenerator key_gen_;
+ ServerBackedStateKeyGenerator state_key_generator_;
scoped_ptr<DBusSignalEmitterInterface> dbus_emitter_;
scoped_ptr<LivenessChecker> liveness_checker_;
const bool enable_browser_abort_on_hang_;