compile cryptohome RPC protos for autotests

This allows us to use MountEx from the cryptohome proxy, and
converts all users of the cryptohome proxy that call mount to
use it.

CQ-DEPEND=CL:1000493
BUG=chromium:809616
TEST=login_OwnershipRetaken login_RemoteOwnership
  login_UserPolicyKeys platform_CryptohomeMigrateChapsTokenClient
  login_RetrieveActiveSessions login_MultiUserPolicy
  login_MultipleSessions

Change-Id: Iccc415dc6233ddce0944fd6e8772c5c5bbf617c5
Reviewed-on: https://chromium-review.googlesource.com/1000693
Commit-Ready: Eric Caruso <ejcaruso@chromium.org>
Tested-by: Eric Caruso <ejcaruso@chromium.org>
Reviewed-by: Andrey Pronin <apronin@chromium.org>
diff --git a/client/cros/cryptohome.py b/client/cros/cryptohome.py
index cf2756b..75dc43a 100644
--- a/client/cros/cryptohome.py
+++ b/client/cros/cryptohome.py
@@ -2,7 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import dbus, gobject, logging, os, random, re, shutil, string, time
+import dbus, gobject, logging, os, random, re, shutil, string, sys, time
 from dbus.mainloop.glib import DBusGMainLoop
 
 import common, constants
@@ -17,6 +17,9 @@
 TEMP_MOUNT_PATTERN = '/home/.shadow/%s/temporary_mount'
 VAULT_PATH_PATTERN = '/home/.shadow/%s/vault'
 
+DBUS_PROTOS_DEP = 'dbus_protos'
+
+
 class ChromiumOSError(error.TestError):
     """Generic error for ChromiumOS-specific exceptions."""
     pass
@@ -593,7 +596,14 @@
     DBUS_PROPERTIES_INTERFACE = 'org.freedesktop.DBus.Properties'
 
 
-    def __init__(self, bus_loop=None):
+    def __init__(self, bus_loop=None, autodir=None, job=None):
+        if autodir and job:
+            # Install D-Bus protos necessary for some methods.
+            dep_dir = os.path.join(autodir, 'deps', DBUS_PROTOS_DEP)
+            job.install_pkg(DBUS_PROTOS_DEP, 'dep', dep_dir)
+            sys.path.append(dep_dir)
+
+        # Set up D-Bus main loop and interface.
         self.main_loop = gobject.MainLoop()
         if bus_loop is None:
             bus_loop = DBusGMainLoop(set_as_default=True)
@@ -661,19 +671,29 @@
         return result
 
 
-    def mount(self, user, password, create=False, async=True):
+    def mount(self, user, password, create=False, async=True, key_label='bar'):
         """Mounts a cryptohome.
 
         Returns True if the mount succeeds or False otherwise.
-        TODO(ellyjones): Migrate mount_vault() to use a multi-user-safe
-        heuristic, then remove this method. See <crosbug.com/20778>.
         """
-        if async:
-            return self.__async_call(self.iface.AsyncMount, user, password,
-                                     create, False, [])['return_status']
-        out = self.__call(self.iface.Mount, user, password, create, False, [])
-        # Sync returns (return code, return status)
-        return out[1] if len(out) > 1 else False
+        import rpc_pb2
+
+        acc = rpc_pb2.AccountIdentifier()
+        acc.account_id = user
+
+        auth = rpc_pb2.AuthorizationRequest()
+        auth.key.secret = password
+        auth.key.data.label = key_label
+
+        mount_req = rpc_pb2.MountRequest()
+        if create:
+            mount_req.create.copy_authorization_key = True
+
+        out = self.__call(self.iface.MountEx, acc.SerializeToString(),
+            auth.SerializeToString(), mount_req.SerializeToString())
+        parsed_out = rpc_pb2.BaseReply()
+        parsed_out.ParseFromString(''.join(map(chr, out)))
+        return parsed_out.error == rpc_pb2.CRYPTOHOME_ERROR_NOT_SET
 
 
     def unmount(self, user):
diff --git a/client/deps/dbus_protos/dbus_protos.py b/client/deps/dbus_protos/dbus_protos.py
new file mode 100644
index 0000000..8750511
--- /dev/null
+++ b/client/deps/dbus_protos/dbus_protos.py
@@ -0,0 +1,36 @@
+#!/usr/bin/python
+
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+"""Compile D-Bus protobuf Python files.
+
+The protos are used by a bunch of cryptohome autotests.
+"""
+
+import os
+import pipes
+from autotest_lib.client.common_lib import utils
+
+version = 1
+
+# These proto definitions are installed by system_api.
+PROTO_DEFS = {
+    'cryptohome': ['key.proto', 'rpc.proto'],
+}
+
+
+def setup(top_dir):
+    sysroot = os.environ['SYSROOT']
+    parent_path = os.path.join(sysroot, 'usr/include/chromeos/dbus/')
+    for subdir, protos in PROTO_DEFS.items():
+        proto_path = os.path.join(parent_path, subdir)
+        cmd = (['protoc', '--proto_path=' + proto_path,
+                '--python_out=' + top_dir] +
+               [os.path.join(proto_path, proto_def) for proto_def in protos])
+    utils.run(' '.join(pipes.quote(arg) for arg in cmd))
+    return
+
+
+pwd = os.getcwd()
+utils.update_version(os.path.join(pwd, 'src'), False, version, setup, pwd)
diff --git a/client/site_tests/login_MultiUserPolicy/login_MultiUserPolicy.py b/client/site_tests/login_MultiUserPolicy/login_MultiUserPolicy.py
index f544aaa..49dca82 100644
--- a/client/site_tests/login_MultiUserPolicy/login_MultiUserPolicy.py
+++ b/client/site_tests/login_MultiUserPolicy/login_MultiUserPolicy.py
@@ -31,7 +31,8 @@
         # policy or key lingering around. At this stage the session isn't
         # started and there's no user signed in.
         ownership.restart_ui_to_clear_ownership_files()
-        cryptohome_proxy = cryptohome.CryptohomeProxy(self._bus_loop)
+        cryptohome_proxy = cryptohome.CryptohomeProxy(
+            self._bus_loop, self.autodir, self.job)
         cryptohome_proxy.ensure_clean_cryptohome_for(self._user1)
         cryptohome_proxy.ensure_clean_cryptohome_for(self._user2)
 
diff --git a/client/site_tests/login_MultipleSessions/login_MultipleSessions.py b/client/site_tests/login_MultipleSessions/login_MultipleSessions.py
index c410455..df97885 100644
--- a/client/site_tests/login_MultipleSessions/login_MultipleSessions.py
+++ b/client/site_tests/login_MultipleSessions/login_MultipleSessions.py
@@ -30,7 +30,8 @@
                 gobject.MainLoop())
         self._listener.listen_for_new_key_and_policy()
 
-        self._cryptohome_proxy = cryptohome.CryptohomeProxy(self._bus_loop)
+        self._cryptohome_proxy = cryptohome.CryptohomeProxy(
+            self._bus_loop, self.autodir, self.job)
 
 
     def run_once(self):
diff --git a/client/site_tests/login_OwnershipRetaken/login_OwnershipRetaken.py b/client/site_tests/login_OwnershipRetaken/login_OwnershipRetaken.py
index 9e0d542..464c853 100644
--- a/client/site_tests/login_OwnershipRetaken/login_OwnershipRetaken.py
+++ b/client/site_tests/login_OwnershipRetaken/login_OwnershipRetaken.py
@@ -27,7 +27,8 @@
         policy.install_protobufs(self.autodir, self.job)
 
         bus_loop = DBusGMainLoop(set_as_default=True)
-        self._cryptohome_proxy = cryptohome.CryptohomeProxy(bus_loop)
+        self._cryptohome_proxy = \
+            cryptohome.CryptohomeProxy(bus_loop, self.autodir, self.job)
         self._cryptohome_proxy.remove(ownership.TESTUSER)
 
         self._sm = session_manager.connect(bus_loop)
diff --git a/client/site_tests/login_RemoteOwnership/login_RemoteOwnership.py b/client/site_tests/login_RemoteOwnership/login_RemoteOwnership.py
index 680d15c..ee27698 100644
--- a/client/site_tests/login_RemoteOwnership/login_RemoteOwnership.py
+++ b/client/site_tests/login_RemoteOwnership/login_RemoteOwnership.py
@@ -26,7 +26,8 @@
         policy.install_protobufs(self.autodir, self.job)
 
         bus_loop = DBusGMainLoop(set_as_default=True)
-        self._cryptohome_proxy = cryptohome.CryptohomeProxy(bus_loop)
+        self._cryptohome_proxy = cryptohome.CryptohomeProxy(
+            bus_loop, self.autodir, self.job)
         self._sm = session_manager.connect(bus_loop)
 
 
diff --git a/client/site_tests/login_RetrieveActiveSessions/login_RetrieveActiveSessions.py b/client/site_tests/login_RetrieveActiveSessions/login_RetrieveActiveSessions.py
index 43c1bf7..734adc8 100644
--- a/client/site_tests/login_RetrieveActiveSessions/login_RetrieveActiveSessions.py
+++ b/client/site_tests/login_RetrieveActiveSessions/login_RetrieveActiveSessions.py
@@ -25,7 +25,8 @@
         bus_loop = DBusGMainLoop(set_as_default=True)
         sm = session_manager.connect(bus_loop)
 
-        cryptohome_proxy = cryptohome.CryptohomeProxy(bus_loop)
+        cryptohome_proxy = cryptohome.CryptohomeProxy(
+            bus_loop, self.autodir, self.job)
         users = ['first_user@nowhere.com', 'second_user@nowhere.com']
         for user in users:
             cryptohome_proxy.ensure_clean_cryptohome_for(user)
diff --git a/client/site_tests/login_UserPolicyKeys/login_UserPolicyKeys.py b/client/site_tests/login_UserPolicyKeys/login_UserPolicyKeys.py
index a2e9557..8b885e3 100644
--- a/client/site_tests/login_UserPolicyKeys/login_UserPolicyKeys.py
+++ b/client/site_tests/login_UserPolicyKeys/login_UserPolicyKeys.py
@@ -65,7 +65,8 @@
         super(login_UserPolicyKeys, self).initialize()
         policy.install_protobufs(self.autodir, self.job)
         self._bus_loop = DBusGMainLoop(set_as_default=True)
-        self._cryptohome_proxy = cryptohome.CryptohomeProxy(self._bus_loop)
+        self._cryptohome_proxy = cryptohome.CryptohomeProxy(
+            self._bus_loop, self.autodir, self.job)
 
         # Clear the user's vault, to make sure the test starts without any
         # policy or key lingering around. At this stage the session isn't
diff --git a/client/site_tests/platform_CryptohomeMigrateChapsTokenClient/platform_CryptohomeMigrateChapsTokenClient.py b/client/site_tests/platform_CryptohomeMigrateChapsTokenClient/platform_CryptohomeMigrateChapsTokenClient.py
index ff18a92..45daa54 100644
--- a/client/site_tests/platform_CryptohomeMigrateChapsTokenClient/platform_CryptohomeMigrateChapsTokenClient.py
+++ b/client/site_tests/platform_CryptohomeMigrateChapsTokenClient/platform_CryptohomeMigrateChapsTokenClient.py
@@ -2,6 +2,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+from dbus.mainloop.glib import DBusGMainLoop
+
 from autotest_lib.client.bin import test
 from autotest_lib.client.common_lib import error
 from autotest_lib.client.cros import cryptohome, pkcs11
@@ -17,7 +19,9 @@
 
     def initialize(self):
         super(platform_CryptohomeMigrateChapsTokenClient, self).initialize()
-        self._cryptohome_proxy = cryptohome.CryptohomeProxy()
+        bus_loop = DBusGMainLoop(set_as_default=True)
+        self._cryptohome_proxy = cryptohome.CryptohomeProxy(
+            bus_loop, self.autodir, self.job)
 
     def run_once(self, generate_key=False):