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