Home | History | Annotate | Download | only in cros
      1 # Copyright 2014 The Chromium OS Authors. All rights reserved.
      2 # Use of this source code is governed by a BSD-style license that can be
      3 # found in the LICENSE file.
      4 
      5 import logging, os
      6 import time
      7 
      8 from autotest_lib.client.common_lib import error
      9 
     10 
     11 _PASSWD_FILE = '/var/tmp/tpm_password'
     12 _RM_DIRS = ('/home/.shadow/* ' +
     13             '/home/chronos/.oobe_completed ' +
     14             '/home/chronos/Local\ State ' +
     15             '/var/cache/app_pack ' +
     16             '/var/cache/shill/default.profile ' +
     17             '/var/lib/tpm ' +
     18             '/var/lib/whitelist/* ')
     19 
     20 
     21 class NoTPMPasswordException(Exception):
     22     """No TPM Password could be found."""
     23     pass
     24 
     25 
     26 def TPMStatus(client):
     27     """Returns a dictionary with TPM status.
     28 
     29     @param client: client object to run commands on.
     30     """
     31     out = client.run('cryptohome --action=tpm_status').stdout.strip()
     32     out = out.replace('TPM ', '')
     33     lines = out.split('\n')
     34     status = {}
     35     for item in lines:
     36         item = item.split(':')
     37         if not item[0]:
     38             continue
     39         if len(item) == 1:
     40             item.append('')
     41         item = map(lambda x : x.strip(), item)
     42         item[1] = True if item[1] == 'true' else item[1]
     43         item[1] = False if item[1] == 'false' else item[1]
     44         status[item[0]] = item[1]
     45     return status
     46 
     47 
     48 def IsTPMAvailable(client):
     49     """Returns True if the TPM is unowned and enabled.
     50 
     51     @param client: client object to run commands on.
     52     """
     53     status = TPMStatus(client)
     54     return status['Enabled'] and not status['Owned']
     55 
     56 
     57 def ClearTPMServer(client, out_dir):
     58     """Clears the TPM and reboots from a server-side autotest.
     59 
     60     @param client: client object to run commands on.
     61     @param out_dir: temporary directory to store the retrieved password file.
     62     """
     63     if IsTPMAvailable(client):
     64         logging.debug('TPM is not owned')
     65         return
     66 
     67     client.run('stop ui')
     68     try:
     69         password = TPMStatus(client)['Password']
     70         if not password:
     71             try:
     72                 client.get_file(_PASSWD_FILE, out_dir)
     73             except error.AutoservRunError:
     74                 raise NoTPMPasswordException(
     75                         'TPM Password file %s doesn\'t exist, falling back on '
     76                         'clear_tpm_owner_request to clear the TPM. You may '
     77                         'need to have the firmware clear the TPM, for instance '
     78                         'by toggling the dev switch.' % _PASSWD_FILE)
     79             with open(os.path.join(out_dir,
     80                       os.path.basename(_PASSWD_FILE))) as f:
     81                 password = f.read().rstrip()
     82         if not password:
     83             raise NoTPMPasswordException(
     84                     'TPM Password file %s empty, falling back on '
     85                     'clear_tpm_owner_request to clear the TPM. You may need to '
     86                     'have the firmware clear the TPM, for instance by toggling '
     87                     'the dev switch.' % _PASSWD_FILE)
     88 
     89         res = client.run('tpm_clear --pass ' + password).stdout.strip()
     90         logging.warn(repr(res))
     91     except NoTPMPasswordException as e:
     92         logging.warn(e.args[0])
     93         client.run('crossystem clear_tpm_owner_request=1')
     94 
     95     CleanupAndReboot(client)
     96 
     97 
     98 def ClearTPMOwnerRequest(client, wait_for_ready=False, timeout=60):
     99     """Clears the TPM using crossystem command.
    100 
    101     @param client: client object to run commands on.
    102     @param wait_for_ready: wait until the TPM status is ready
    103     @param timeout: number of seconds to wait for the TPM to become ready.
    104     """
    105     if not client.run('crossystem clear_tpm_owner_request=1',
    106                       ignore_status=True).exit_status == 0:
    107         raise error.TestFail('Unable to clear TPM.')
    108 
    109     CleanupAndReboot(client)
    110 
    111     if wait_for_ready:
    112         status = ''
    113         end_time = time.time() + timeout
    114         # Wait for cryptohome to send a successful reply.
    115         while 'GetTpmStatus success' not in status and time.time() < end_time:
    116             status = client.run('cryptohome --action=tpm_more_status',
    117                     ignore_status=True).stdout.strip()
    118             logging.debug(status)
    119             time.sleep(1)
    120 
    121 
    122 def CleanupAndReboot(client):
    123     """Cleanup and reboot the device.
    124 
    125     @param client: client object to run commands on.
    126     """
    127     client.run('sudo rm -rf ' + _RM_DIRS, ignore_status=True)
    128     client.run('sync', ignore_status=True)
    129     client.reboot()
    130