blob: ea6fb8d5b0e9b203fb1595383cde3a519c76df01 [file] [log] [blame]
Frank Farzand5e36312012-01-13 14:34:03 -08001# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Chris Masone5e06f182010-03-23 08:29:52 -07002# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
Will Drewry9e440792013-12-11 17:18:35 -06005import dbus, gobject, logging, os, random, re, shutil, string
6from dbus.mainloop.glib import DBusGMainLoop
barfab@chromium.orgb6d29932012-04-11 09:46:43 +02007
8import common, constants
barfab@chromium.org5c374632012-04-05 16:50:56 +02009from autotest_lib.client.bin import utils
Chris Masone5e06f182010-03-23 08:29:52 -070010from autotest_lib.client.common_lib import error
Will Drewry9e440792013-12-11 17:18:35 -060011from autotest_lib.client.cros.cros_disks import DBusClient
Eric Lic4d8f4a2010-12-10 09:49:23 -080012
Sean Oe5d8fd02010-09-30 10:44:44 +020013CRYPTOHOME_CMD = '/usr/sbin/cryptohome'
Elly Fong-Jones6cb26ad2013-05-21 12:09:23 -040014GUEST_USER_NAME = '$guest'
Sean Oe5d8fd02010-09-30 10:44:44 +020015
Chris Masone5d010aa2013-05-06 14:38:42 -070016class ChromiumOSError(error.TestError):
Sean Oe5d8fd02010-09-30 10:44:44 +020017 """Generic error for ChromiumOS-specific exceptions."""
18 pass
19
Sean Oe5d8fd02010-09-30 10:44:44 +020020def __run_cmd(cmd):
21 return utils.system_output(cmd + ' 2>&1', retain_output=True,
22 ignore_status=True).strip()
23
Sean Oe5d8fd02010-09-30 10:44:44 +020024def get_user_hash(user):
barfab@chromium.org5c374632012-04-05 16:50:56 +020025 """Get the user hash for the given user."""
Elly Fong-Jones6cb26ad2013-05-21 12:09:23 -040026 return utils.system_output(['cryptohome', '--action=obfuscate_user',
27 '--user=%s' % user])
Sean Oe5d8fd02010-09-30 10:44:44 +020028
29
barfab@chromium.org5c374632012-04-05 16:50:56 +020030def user_path(user):
31 """Get the user mount point for the given user."""
Elly Fong-Jones6cb26ad2013-05-21 12:09:23 -040032 return utils.system_output(['cryptohome-path', 'user', user])
barfab@chromium.org5c374632012-04-05 16:50:56 +020033
34
35def system_path(user):
36 """Get the system mount point for the given user."""
Elly Fong-Jones6cb26ad2013-05-21 12:09:23 -040037 return utils.system_output(['cryptohome-path', 'system', user])
barfab@chromium.org5c374632012-04-05 16:50:56 +020038
39
Chris Masone5d010aa2013-05-06 14:38:42 -070040def ensure_clean_cryptohome_for(user, password=None):
41 """Ensure a fresh cryptohome exists for user.
42
43 @param user: user who needs a shiny new cryptohome.
44 @param password: if unset, a random password will be used.
45 """
46 if not password:
47 password = ''.join(random.sample(string.ascii_lowercase, 6))
48 remove_vault(user)
49 mount_vault(user, password, create=True)
50
51
Frank Farzand5e36312012-01-13 14:34:03 -080052def get_tpm_status():
53 """Get the TPM status.
54
55 Returns:
56 A TPM status dictionary, for example:
57 { 'Enabled': True,
58 'Owned': True,
59 'Being Owned': False,
60 'Ready': True,
61 'Password': ''
62 }
63 """
64 out = __run_cmd(CRYPTOHOME_CMD + ' --action=tpm_status')
65 status = {}
66 for field in ['Enabled', 'Owned', 'Being Owned', 'Ready']:
67 match = re.search('TPM %s: (true|false)' % field, out)
68 if not match:
69 raise ChromiumOSError('Invalid TPM status: "%s".' % out)
70 status[field] = match.group(1) == 'true'
71 match = re.search('TPM Password: (\w*)', out)
72 status['Password'] = ''
73 if match:
74 status['Password'] = match.group(1)
75 return status
76
77
Darren Krahn5f880f62012-10-02 15:17:59 -070078def get_tpm_attestation_status():
79 """Get the TPM attestation status. Works similar to get_tpm_status().
80 """
81 out = __run_cmd(CRYPTOHOME_CMD + ' --action=tpm_attestation_status')
82 status = {}
83 for field in ['Prepared', 'Enrolled']:
84 match = re.search('Attestation %s: (true|false)' % field, out)
85 if not match:
86 raise ChromiumOSError('Invalid attestation status: "%s".' % out)
87 status[field] = match.group(1) == 'true'
88 return status
89
90
Frank Farzand5e36312012-01-13 14:34:03 -080091def take_tpm_ownership():
92 """Take TPM owernship.
93
94 Blocks until TPM is owned.
95 """
96 __run_cmd(CRYPTOHOME_CMD + ' --action=tpm_take_ownership')
97 __run_cmd(CRYPTOHOME_CMD + ' --action=tpm_wait_ownership')
98
99
Darren Krahn0e73e7f2012-09-05 15:35:15 -0700100def verify_ek():
101 """Verify the TPM endorsement key.
102
103 Returns true if EK is valid.
104 """
105 cmd = CRYPTOHOME_CMD + ' --action=tpm_verify_ek'
106 return (utils.system(cmd, ignore_status=True) == 0)
107
108
Sean Oe5d8fd02010-09-30 10:44:44 +0200109def remove_vault(user):
barfab@chromium.org5c374632012-04-05 16:50:56 +0200110 """Remove the given user's vault from the shadow directory."""
Sean Oe5d8fd02010-09-30 10:44:44 +0200111 logging.debug('user is %s', user)
112 user_hash = get_user_hash(user)
barfab@chromium.org5c374632012-04-05 16:50:56 +0200113 logging.debug('Removing vault for user %s with hash %s' % (user, user_hash))
Sean Oe5d8fd02010-09-30 10:44:44 +0200114 cmd = CRYPTOHOME_CMD + ' --action=remove --force --user=%s' % user
115 __run_cmd(cmd)
barfab@chromium.org5c374632012-04-05 16:50:56 +0200116 # Ensure that the vault does not exist.
117 if os.path.exists(os.path.join(constants.SHADOW_ROOT, user_hash)):
Darren Krahne6c44b92014-03-31 12:11:08 -0700118 raise ChromiumOSError('Cryptohome could not remove the user\'s vault.')
Sean Oe5d8fd02010-09-30 10:44:44 +0200119
120
barfab@chromium.orgcf2151e2012-04-04 15:39:34 +0200121def remove_all_vaults():
122 """Remove any existing vaults from the shadow directory.
123
124 This function must be run with root privileges.
125 """
barfab@chromium.org5c374632012-04-05 16:50:56 +0200126 for item in os.listdir(constants.SHADOW_ROOT):
127 abs_item = os.path.join(constants.SHADOW_ROOT, item)
barfab@chromium.orgcf2151e2012-04-04 15:39:34 +0200128 if os.path.isdir(os.path.join(abs_item, 'vault')):
129 logging.debug('Removing vault for user with hash %s' % item)
130 shutil.rmtree(abs_item)
131
132
Sean Oe5d8fd02010-09-30 10:44:44 +0200133def mount_vault(user, password, create=False):
barfab@chromium.org5c374632012-04-05 16:50:56 +0200134 """Mount the given user's vault."""
Elly Fong-Jones6cb26ad2013-05-21 12:09:23 -0400135 args = [CRYPTOHOME_CMD, '--action=mount', '--user=%s' % user,
Chris Masone3543e512013-11-04 13:09:30 -0800136 '--password=%s' % password, '--async']
Sean Oe5d8fd02010-09-30 10:44:44 +0200137 if create:
Elly Fong-Jones6cb26ad2013-05-21 12:09:23 -0400138 args.append('--create')
Chris Masone3543e512013-11-04 13:09:30 -0800139 logging.info(__run_cmd(' '.join(args)))
barfab@chromium.org5c374632012-04-05 16:50:56 +0200140 # Ensure that the vault exists in the shadow directory.
Sean Oe5d8fd02010-09-30 10:44:44 +0200141 user_hash = get_user_hash(user)
barfab@chromium.org5c374632012-04-05 16:50:56 +0200142 if not os.path.exists(os.path.join(constants.SHADOW_ROOT, user_hash)):
Sean Oe5d8fd02010-09-30 10:44:44 +0200143 raise ChromiumOSError('Cryptohome vault not found after mount.')
barfab@chromium.org5c374632012-04-05 16:50:56 +0200144 # Ensure that the vault is mounted.
145 if not is_vault_mounted(
146 user=user,
147 device_regex=constants.CRYPTOHOME_DEV_REGEX_REGULAR_USER,
148 allow_fail=True):
149 raise ChromiumOSError('Cryptohome created a vault but did not mount.')
Sean Oe5d8fd02010-09-30 10:44:44 +0200150
151
Chris Masone5d010aa2013-05-06 14:38:42 -0700152def mount_guest():
153 """Mount the given user's vault."""
Chris Masone3543e512013-11-04 13:09:30 -0800154 args = [CRYPTOHOME_CMD, '--action=mount_guest', '--async']
155 logging.info(__run_cmd(' '.join(args)))
Chris Masone5d010aa2013-05-06 14:38:42 -0700156 # Ensure that the guest tmpfs is mounted.
157 if not is_guest_vault_mounted(allow_fail=True):
158 raise ChromiumOSError('Cryptohome did not mount tmpfs.')
159
160
Sean Oe5d8fd02010-09-30 10:44:44 +0200161def test_auth(user, password):
Elly Fong-Jones6cb26ad2013-05-21 12:09:23 -0400162 cmd = [CRYPTOHOME_CMD, '--action=test_auth', '--user=%s' % user,
163 '--password=%s' % password, '--async']
164 return 'Authentication succeeded' in utils.system_output(cmd)
Sean Oe5d8fd02010-09-30 10:44:44 +0200165
166
Elly Fong-Jones6cb26ad2013-05-21 12:09:23 -0400167def unmount_vault(user):
barfab@chromium.org5c374632012-04-05 16:50:56 +0200168 """Unmount the given user's vault.
169
170 Once unmounting for a specific user is supported, the user parameter will
171 name the target user. See crosbug.com/20778.
Elly Jones686c2f42011-10-24 16:45:07 -0400172 """
Chris Masone3543e512013-11-04 13:09:30 -0800173 __run_cmd(CRYPTOHOME_CMD + ' --action=unmount')
barfab@chromium.org5c374632012-04-05 16:50:56 +0200174 # Ensure that the vault is not mounted.
Elly Fong-Jones6cb26ad2013-05-21 12:09:23 -0400175 if is_vault_mounted(user, allow_fail=True):
Sean Oe5d8fd02010-09-30 10:44:44 +0200176 raise ChromiumOSError('Cryptohome did not unmount the user.')
177
178
barfab@chromium.org5c374632012-04-05 16:50:56 +0200179def __get_mount_info(mount_point, allow_fail=False):
180 """Get information about the active mount at a given mount point."""
beeps569f8672013-08-07 10:18:51 -0700181 cryptohomed_path = '/proc/$(pgrep cryptohomed)/mounts'
182 try:
183 logging.info(utils.system_output('cat %s' % cryptohomed_path))
184 mount_line = utils.system_output(
185 'grep %s %s' % (mount_point, cryptohomed_path),
186 ignore_status=allow_fail)
187 except Exception as e:
188 logging.error(e)
189 raise ChromiumOSError('Could not get info about cryptohome vault '
190 'through %s. See logs for complete mount-point.'
191 % os.path.dirname(str(mount_point)))
Sourav Poddar574bd622010-05-26 14:22:26 +0530192 return mount_line.split()
193
194
Elly Fong-Jones6cb26ad2013-05-21 12:09:23 -0400195def __get_user_mount_info(user, allow_fail=False):
barfab@chromium.org5c374632012-04-05 16:50:56 +0200196 """Get information about the active mounts for a given user.
197
198 Returns the active mounts at the user's user and system mount points. If no
199 user is given, the active mount at the shared mount point is returned
200 (regular users have a bind-mount at this mount point for backwards
201 compatibility; the guest user has a mount at this mount point only).
202 """
Elly Fong-Jones6cb26ad2013-05-21 12:09:23 -0400203 return [__get_mount_info(mount_point=user_path(user),
204 allow_fail=allow_fail),
205 __get_mount_info(mount_point=system_path(user),
206 allow_fail=allow_fail)]
Jim Hebertf08f88d2011-04-22 10:33:49 -0700207
barfab@chromium.org5c374632012-04-05 16:50:56 +0200208def is_vault_mounted(
Elly Fong-Jones6cb26ad2013-05-21 12:09:23 -0400209 user,
barfab@chromium.org5c374632012-04-05 16:50:56 +0200210 device_regex=constants.CRYPTOHOME_DEV_REGEX_ANY,
211 fs_regex=constants.CRYPTOHOME_FS_REGEX_ANY,
212 allow_fail=False):
213 """Check whether a vault is mounted for the given user.
214
215 If no user is given, the shared mount point is checked, determining whether
216 a vault is mounted for any user.
217 """
218 user_mount_info = __get_user_mount_info(user=user, allow_fail=allow_fail)
219 for mount_info in user_mount_info:
220 if (len(mount_info) < 3 or
221 not re.match(device_regex, mount_info[0]) or
222 not re.match(fs_regex, mount_info[2])):
223 return False
224 return True
Sourav Poddar574bd622010-05-26 14:22:26 +0530225
226
barfab@chromium.org5c374632012-04-05 16:50:56 +0200227def is_guest_vault_mounted(allow_fail=False):
228 """Check whether a vault backed by tmpfs is mounted for the guest user."""
229 return is_vault_mounted(
Elly Fong-Jones6cb26ad2013-05-21 12:09:23 -0400230 user=GUEST_USER_NAME,
barfab@chromium.org5c374632012-04-05 16:50:56 +0200231 device_regex=constants.CRYPTOHOME_DEV_REGEX_GUEST,
232 fs_regex=constants.CRYPTOHOME_FS_REGEX_TMPFS,
233 allow_fail=allow_fail)
234
235
Elly Fong-Jones6cb26ad2013-05-21 12:09:23 -0400236def get_mounted_vault_devices(user, allow_fail=False):
barfab@chromium.org5c374632012-04-05 16:50:56 +0200237 """Get the device(s) backing the vault mounted for the given user.
238
239 Returns the devices mounted at the user's user and system mount points. If
240 no user is given, the device mounted at the shared mount point is returned.
241 """
242 return [mount_info[0]
243 for mount_info
244 in __get_user_mount_info(user=user, allow_fail=allow_fail)
245 if len(mount_info)]
Nirnimesh66814492011-06-27 18:00:33 -0700246
247
248def canonicalize(credential):
barfab@chromium.org5c374632012-04-05 16:50:56 +0200249 """Perform basic canonicalization of |email_address|.
Nirnimesh66814492011-06-27 18:00:33 -0700250
barfab@chromium.org5c374632012-04-05 16:50:56 +0200251 Perform basic canonicalization of |email_address|, taking into account that
252 gmail does not consider '.' or caps inside a username to matter. It also
253 ignores everything after a '+'. For example,
254 c.masone+abc@gmail.com == cMaSone@gmail.com, per
Nirnimesh66814492011-06-27 18:00:33 -0700255 http://mail.google.com/support/bin/answer.py?hl=en&ctx=mail&answer=10313
256 """
257 if not credential:
258 return None
259
260 parts = credential.split('@')
261 if len(parts) != 2:
barfab@chromium.org5c374632012-04-05 16:50:56 +0200262 raise error.TestError('Malformed email: ' + credential)
Nirnimesh66814492011-06-27 18:00:33 -0700263
264 (name, domain) = parts
265 name = name.partition('+')[0]
barfab@chromium.org5c374632012-04-05 16:50:56 +0200266 if (domain == constants.SPECIAL_CASE_DOMAIN):
Nirnimesh66814492011-06-27 18:00:33 -0700267 name = name.replace('.', '')
268 return '@'.join([name, domain]).lower()
Elly Jones686c2f42011-10-24 16:45:07 -0400269
barfab@chromium.orgcf2151e2012-04-04 15:39:34 +0200270
Will Drewryd2fed972013-12-05 16:35:51 -0600271def crash_cryptohomed():
Will Drewrydc2b0dd2013-12-10 16:41:04 -0600272 # Try to kill cryptohomed so we get something to work with.
273 pid = __run_cmd('pgrep cryptohomed')
274 try:
Will Drewry9e440792013-12-11 17:18:35 -0600275 pid = int(pid)
Will Drewrydc2b0dd2013-12-10 16:41:04 -0600276 except ValueError, e: # empty or invalid string
Will Drewry9e440792013-12-11 17:18:35 -0600277 raise error.TestError('Cryptohomed was not running')
Will Drewrydc2b0dd2013-12-10 16:41:04 -0600278 utils.system('kill -ABRT %d' % pid)
279 # CONT just in case cryptohomed had a spurious STOP.
280 utils.system('kill -CONT %d' % pid)
281 utils.poll_for_condition(
282 lambda: utils.system('ps -p %d' % pid,
283 ignore_status=True) != 0,
Will Drewry934d1532014-01-30 16:23:17 -0600284 timeout=180,
Will Drewrydc2b0dd2013-12-10 16:41:04 -0600285 exception=error.TestError(
286 'Timeout waiting for cryptohomed to coredump'))
287
Will Drewryd2fed972013-12-05 16:35:51 -0600288
Will Drewry9e440792013-12-11 17:18:35 -0600289class CryptohomeProxy(DBusClient):
290 """A DBus proxy client for testing the Cryptohome DBus server.
291 """
292 CRYPTOHOME_BUS_NAME = 'org.chromium.Cryptohome'
293 CRYPTOHOME_OBJECT_PATH = '/org/chromium/Cryptohome'
294 CRYPTOHOME_INTERFACE = 'org.chromium.CryptohomeInterface'
295 ASYNC_CALL_STATUS_SIGNAL = 'AsyncCallStatus'
296 ASYNC_CALL_STATUS_SIGNAL_ARGUMENTS = (
297 'async_id', 'return_status', 'return_code'
298 )
299 DBUS_PROPERTIES_INTERFACE = 'org.freedesktop.DBus.Properties'
300
Chris Masone19e305e2014-03-14 15:13:46 -0700301
Chris Masone64170f82014-03-14 15:47:05 -0700302 def __init__(self, bus_loop=None):
Will Drewry9e440792013-12-11 17:18:35 -0600303 self.main_loop = gobject.MainLoop()
Will Drewry78db9dc2014-04-01 16:34:23 -0500304 if bus_loop is None:
Chris Masone64170f82014-03-14 15:47:05 -0700305 bus_loop = DBusGMainLoop(set_as_default=True)
Will Drewry9e440792013-12-11 17:18:35 -0600306 self.bus = dbus.SystemBus(mainloop=bus_loop)
307 super(CryptohomeProxy, self).__init__(self.main_loop, self.bus,
308 self.CRYPTOHOME_BUS_NAME,
309 self.CRYPTOHOME_OBJECT_PATH)
310 self.iface = dbus.Interface(self.proxy_object,
311 self.CRYPTOHOME_INTERFACE)
312 self.properties = dbus.Interface(self.proxy_object,
313 self.DBUS_PROPERTIES_INTERFACE)
314 self.handle_signal(self.CRYPTOHOME_INTERFACE,
315 self.ASYNC_CALL_STATUS_SIGNAL,
316 self.ASYNC_CALL_STATUS_SIGNAL_ARGUMENTS)
Elly Jones2f0ebba2011-10-27 13:43:20 -0400317
Chris Masone19e305e2014-03-14 15:13:46 -0700318
Will Drewryd2fed972013-12-05 16:35:51 -0600319 # Wrap all proxied calls to catch cryptohomed failures.
320 def __call(self, method, *args):
321 try:
Chris Masonef59d9df2014-03-14 12:05:32 -0700322 return method(*args, timeout=180)
Will Drewryd2fed972013-12-05 16:35:51 -0600323 except dbus.exceptions.DBusException, e:
324 if e.get_dbus_name() == 'org.freedesktop.DBus.Error.NoReply':
325 logging.error('Cryptohome is not responding. Sending ABRT')
326 crash_cryptohomed()
327 raise ChromiumOSError('cryptohomed aborted. Check crashes!')
328 raise e
329
Chris Masone19e305e2014-03-14 15:13:46 -0700330
Will Drewry9e440792013-12-11 17:18:35 -0600331 def __wait_for_specific_signal(self, signal, data):
332 """Wait for the |signal| with matching |data|
333 Returns the resulting dict on success or {} on error.
334 """
Will Drewryc4de5ff2014-02-03 13:26:57 -0600335 # Do not bubble up the timeout here, just return {}.
336 result = {}
337 try:
338 result = self.wait_for_signal(signal)
339 except utils.TimeoutError:
340 return {}
Will Drewry9e440792013-12-11 17:18:35 -0600341 for k in data.keys():
342 if not result.has_key(k) or result[k] != data[k]:
343 return {}
344 return result
345
Chris Masone19e305e2014-03-14 15:13:46 -0700346
Will Drewry9e440792013-12-11 17:18:35 -0600347 # Perform a data-less async call.
348 # TODO(wad) Add __async_data_call.
349 def __async_call(self, method, *args):
Will Drewryfef135a2014-05-23 16:02:14 -0500350 # Clear out any superfluous async call signals.
351 self.clear_signal_content(self.ASYNC_CALL_STATUS_SIGNAL)
Will Drewry9e440792013-12-11 17:18:35 -0600352 out = self.__call(method, *args)
353 logging.debug('Issued call ' + str(method) +
354 ' with async_id ' + str(out))
355 result = {}
356 try:
Will Drewry934d1532014-01-30 16:23:17 -0600357 # __wait_for_specific_signal has a 10s timeout
Will Drewry9e440792013-12-11 17:18:35 -0600358 result = utils.poll_for_condition(
359 lambda: self.__wait_for_specific_signal(
360 self.ASYNC_CALL_STATUS_SIGNAL, {'async_id' : out}),
Will Drewry934d1532014-01-30 16:23:17 -0600361 timeout=180,
Will Drewry9e440792013-12-11 17:18:35 -0600362 desc='matching %s signal' % self.ASYNC_CALL_STATUS_SIGNAL)
363 except utils.TimeoutError, e:
364 logging.error('Cryptohome timed out. Sending ABRT.')
365 crash_cryptohomed()
366 raise ChromiumOSError('cryptohomed aborted. Check crashes!')
367 return result
368
Chris Masone19e305e2014-03-14 15:13:46 -0700369
Will Drewry9e440792013-12-11 17:18:35 -0600370 def mount(self, user, password, create=False, async=True):
Elly Jones2f0ebba2011-10-27 13:43:20 -0400371 """Mounts a cryptohome.
372
373 Returns True if the mount succeeds or False otherwise.
374 TODO(ellyjones): Migrate mount_vault() to use a multi-user-safe
375 heuristic, then remove this method. See <crosbug.com/20778>.
376 """
Will Drewry9e440792013-12-11 17:18:35 -0600377 if async:
378 return self.__async_call(self.iface.AsyncMount, user, password,
379 create, False, [])['return_status']
Will Drewryd2fed972013-12-05 16:35:51 -0600380 out = self.__call(self.iface.Mount, user, password, create, False, [])
Will Drewry9e440792013-12-11 17:18:35 -0600381 # Sync returns (return code, return status)
382 return out[1] if len(out) > 1 else False
Elly Jones2f0ebba2011-10-27 13:43:20 -0400383
Chris Masone19e305e2014-03-14 15:13:46 -0700384
Elly Jones2f0ebba2011-10-27 13:43:20 -0400385 def unmount(self, user):
386 """Unmounts a cryptohome.
387
388 Returns True if the unmount suceeds or false otherwise.
389 TODO(ellyjones): Once there's a per-user unmount method, use it. See
390 <crosbug.com/20778>.
391 """
Will Drewryd2fed972013-12-05 16:35:51 -0600392 return self.__call(self.iface.Unmount)
Elly Jones2f0ebba2011-10-27 13:43:20 -0400393
Chris Masone19e305e2014-03-14 15:13:46 -0700394
Elly Jones2f0ebba2011-10-27 13:43:20 -0400395 def is_mounted(self, user):
396 """Tests whether a user's cryptohome is mounted."""
397 return (utils.is_mountpoint(user_path(user))
398 and utils.is_mountpoint(system_path(user)))
399
Chris Masone19e305e2014-03-14 15:13:46 -0700400
Elly Jones2f0ebba2011-10-27 13:43:20 -0400401 def require_mounted(self, user):
402 """Raises a test failure if a user's cryptohome is not mounted."""
403 utils.require_mountpoint(user_path(user))
404 utils.require_mountpoint(system_path(user))
Elly Jones4458f442012-04-16 15:42:56 -0400405
Chris Masone19e305e2014-03-14 15:13:46 -0700406
Will Drewry9e440792013-12-11 17:18:35 -0600407 def migrate(self, user, oldkey, newkey, async=True):
Elly Jones4458f442012-04-16 15:42:56 -0400408 """Migrates the specified user's cryptohome from one key to another."""
Will Drewry9e440792013-12-11 17:18:35 -0600409 if async:
410 return self.__async_call(self.iface.AsyncMigrateKey,
411 user, oldkey, newkey)['return_status']
Will Drewryd2fed972013-12-05 16:35:51 -0600412 return self.__call(self.iface.MigrateKey, user, oldkey, newkey)
Elly Jones4458f442012-04-16 15:42:56 -0400413
Chris Masone19e305e2014-03-14 15:13:46 -0700414
Will Drewry9e440792013-12-11 17:18:35 -0600415 def remove(self, user, async=True):
416 if async:
417 return self.__async_call(self.iface.AsyncRemove,
418 user)['return_status']
Will Drewryd2fed972013-12-05 16:35:51 -0600419 return self.__call(self.iface.Remove, user)
Chris Masone19e305e2014-03-14 15:13:46 -0700420
421
422 def ensure_clean_cryptohome_for(self, user, password=None):
423 """Ensure a fresh cryptohome exists for user.
424
425 @param user: user who needs a shiny new cryptohome.
426 @param password: if unset, a random password will be used.
427 """
428 if not password:
429 password = ''.join(random.sample(string.ascii_lowercase, 6))
430 self.remove(user)
431 self.mount(user, password, create=True)