Home | History | Annotate | Download | only in server
      1 /*
      2  * Copyright (C) 2012 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.server;
     18 
     19 import android.content.BroadcastReceiver;
     20 import android.content.ContentResolver;
     21 import android.content.Context;
     22 import android.content.Intent;
     23 import android.content.IntentFilter;
     24 import android.content.pm.PackageManager;
     25 import android.content.pm.UserInfo;
     26 
     27 import static android.Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE;
     28 import static android.content.Context.USER_SERVICE;
     29 import static android.Manifest.permission.READ_PROFILE;
     30 
     31 import android.database.sqlite.SQLiteDatabase;
     32 import android.os.Binder;
     33 import android.os.IBinder;
     34 import android.os.Process;
     35 import android.os.RemoteException;
     36 import android.os.storage.IMountService;
     37 import android.os.ServiceManager;
     38 import android.os.SystemProperties;
     39 import android.os.UserHandle;
     40 import android.os.UserManager;
     41 import android.provider.Settings;
     42 import android.provider.Settings.Secure;
     43 import android.provider.Settings.SettingNotFoundException;
     44 import android.security.KeyStore;
     45 import android.text.TextUtils;
     46 import android.util.Slog;
     47 
     48 import com.android.internal.widget.ILockSettings;
     49 import com.android.internal.widget.LockPatternUtils;
     50 
     51 import java.util.ArrayList;
     52 import java.util.Arrays;
     53 import java.util.List;
     54 
     55 /**
     56  * Keeps the lock pattern/password data and related settings for each user.
     57  * Used by LockPatternUtils. Needs to be a service because Settings app also needs
     58  * to be able to save lockscreen information for secondary users.
     59  * @hide
     60  */
     61 public class LockSettingsService extends ILockSettings.Stub {
     62 
     63     private static final String PERMISSION = ACCESS_KEYGUARD_SECURE_STORAGE;
     64 
     65     private static final String TAG = "LockSettingsService";
     66 
     67     private final Context mContext;
     68 
     69     private final LockSettingsStorage mStorage;
     70 
     71     private LockPatternUtils mLockPatternUtils;
     72     private boolean mFirstCallToVold;
     73 
     74     public LockSettingsService(Context context) {
     75         mContext = context;
     76         // Open the database
     77 
     78         mLockPatternUtils = new LockPatternUtils(context);
     79         mFirstCallToVold = true;
     80 
     81         IntentFilter filter = new IntentFilter();
     82         filter.addAction(Intent.ACTION_USER_ADDED);
     83         filter.addAction(Intent.ACTION_USER_STARTING);
     84         mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
     85 
     86         mStorage = new LockSettingsStorage(context, new LockSettingsStorage.Callback() {
     87             @Override
     88             public void initialize(SQLiteDatabase db) {
     89                 // Get the lockscreen default from a system property, if available
     90                 boolean lockScreenDisable = SystemProperties.getBoolean(
     91                         "ro.lockscreen.disable.default", false);
     92                 if (lockScreenDisable) {
     93                     mStorage.writeKeyValue(db, LockPatternUtils.DISABLE_LOCKSCREEN_KEY, "1", 0);
     94                 }
     95             }
     96         });
     97     }
     98 
     99     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
    100         @Override
    101         public void onReceive(Context context, Intent intent) {
    102             if (Intent.ACTION_USER_ADDED.equals(intent.getAction())) {
    103                 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
    104                 final int userSysUid = UserHandle.getUid(userHandle, Process.SYSTEM_UID);
    105                 final KeyStore ks = KeyStore.getInstance();
    106 
    107                 // Clear up keystore in case anything was left behind by previous users
    108                 ks.resetUid(userSysUid);
    109 
    110                 // If this user has a parent, sync with its keystore password
    111                 final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
    112                 final UserInfo parentInfo = um.getProfileParent(userHandle);
    113                 if (parentInfo != null) {
    114                     final int parentSysUid = UserHandle.getUid(parentInfo.id, Process.SYSTEM_UID);
    115                     ks.syncUid(parentSysUid, userSysUid);
    116                 }
    117             } else if (Intent.ACTION_USER_STARTING.equals(intent.getAction())) {
    118                 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
    119                 mStorage.prefetchUser(userHandle);
    120             }
    121         }
    122     };
    123 
    124     public void systemReady() {
    125         migrateOldData();
    126         mStorage.prefetchUser(UserHandle.USER_OWNER);
    127     }
    128 
    129     private void migrateOldData() {
    130         try {
    131             // These Settings moved before multi-user was enabled, so we only have to do it for the
    132             // root user.
    133             if (getString("migrated", null, 0) == null) {
    134                 final ContentResolver cr = mContext.getContentResolver();
    135                 for (String validSetting : VALID_SETTINGS) {
    136                     String value = Settings.Secure.getString(cr, validSetting);
    137                     if (value != null) {
    138                         setString(validSetting, value, 0);
    139                     }
    140                 }
    141                 // No need to move the password / pattern files. They're already in the right place.
    142                 setString("migrated", "true", 0);
    143                 Slog.i(TAG, "Migrated lock settings to new location");
    144             }
    145 
    146             // These Settings changed after multi-user was enabled, hence need to be moved per user.
    147             if (getString("migrated_user_specific", null, 0) == null) {
    148                 final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
    149                 final ContentResolver cr = mContext.getContentResolver();
    150                 List<UserInfo> users = um.getUsers();
    151                 for (int user = 0; user < users.size(); user++) {
    152                     // Migrate owner info
    153                     final int userId = users.get(user).id;
    154                     final String OWNER_INFO = Secure.LOCK_SCREEN_OWNER_INFO;
    155                     String ownerInfo = Settings.Secure.getStringForUser(cr, OWNER_INFO, userId);
    156                     if (ownerInfo != null) {
    157                         setString(OWNER_INFO, ownerInfo, userId);
    158                         Settings.Secure.putStringForUser(cr, ownerInfo, "", userId);
    159                     }
    160 
    161                     // Migrate owner info enabled.  Note there was a bug where older platforms only
    162                     // stored this value if the checkbox was toggled at least once. The code detects
    163                     // this case by handling the exception.
    164                     final String OWNER_INFO_ENABLED = Secure.LOCK_SCREEN_OWNER_INFO_ENABLED;
    165                     boolean enabled;
    166                     try {
    167                         int ivalue = Settings.Secure.getIntForUser(cr, OWNER_INFO_ENABLED, userId);
    168                         enabled = ivalue != 0;
    169                         setLong(OWNER_INFO_ENABLED, enabled ? 1 : 0, userId);
    170                     } catch (SettingNotFoundException e) {
    171                         // Setting was never stored. Store it if the string is not empty.
    172                         if (!TextUtils.isEmpty(ownerInfo)) {
    173                             setLong(OWNER_INFO_ENABLED, 1, userId);
    174                         }
    175                     }
    176                     Settings.Secure.putIntForUser(cr, OWNER_INFO_ENABLED, 0, userId);
    177                 }
    178                 // No need to move the password / pattern files. They're already in the right place.
    179                 setString("migrated_user_specific", "true", 0);
    180                 Slog.i(TAG, "Migrated per-user lock settings to new location");
    181             }
    182         } catch (RemoteException re) {
    183             Slog.e(TAG, "Unable to migrate old data", re);
    184         }
    185     }
    186 
    187     private final void checkWritePermission(int userId) {
    188         mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsWrite");
    189     }
    190 
    191     private final void checkPasswordReadPermission(int userId) {
    192         mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsRead");
    193     }
    194 
    195     private final void checkReadPermission(String requestedKey, int userId) {
    196         final int callingUid = Binder.getCallingUid();
    197         for (int i = 0; i < READ_PROFILE_PROTECTED_SETTINGS.length; i++) {
    198             String key = READ_PROFILE_PROTECTED_SETTINGS[i];
    199             if (key.equals(requestedKey) && mContext.checkCallingOrSelfPermission(READ_PROFILE)
    200                     != PackageManager.PERMISSION_GRANTED) {
    201                 throw new SecurityException("uid=" + callingUid
    202                         + " needs permission " + READ_PROFILE + " to read "
    203                         + requestedKey + " for user " + userId);
    204             }
    205         }
    206     }
    207 
    208     @Override
    209     public void setBoolean(String key, boolean value, int userId) throws RemoteException {
    210         checkWritePermission(userId);
    211         setStringUnchecked(key, userId, value ? "1" : "0");
    212     }
    213 
    214     @Override
    215     public void setLong(String key, long value, int userId) throws RemoteException {
    216         checkWritePermission(userId);
    217         setStringUnchecked(key, userId, Long.toString(value));
    218     }
    219 
    220     @Override
    221     public void setString(String key, String value, int userId) throws RemoteException {
    222         checkWritePermission(userId);
    223         setStringUnchecked(key, userId, value);
    224     }
    225 
    226     private void setStringUnchecked(String key, int userId, String value) {
    227         mStorage.writeKeyValue(key, value, userId);
    228     }
    229 
    230     @Override
    231     public boolean getBoolean(String key, boolean defaultValue, int userId) throws RemoteException {
    232         checkReadPermission(key, userId);
    233 
    234         String value = mStorage.readKeyValue(key, null, userId);
    235         return TextUtils.isEmpty(value) ?
    236                 defaultValue : (value.equals("1") || value.equals("true"));
    237     }
    238 
    239     @Override
    240     public long getLong(String key, long defaultValue, int userId) throws RemoteException {
    241         checkReadPermission(key, userId);
    242 
    243         String value = mStorage.readKeyValue(key, null, userId);
    244         return TextUtils.isEmpty(value) ? defaultValue : Long.parseLong(value);
    245     }
    246 
    247     @Override
    248     public String getString(String key, String defaultValue, int userId) throws RemoteException {
    249         checkReadPermission(key, userId);
    250 
    251         return mStorage.readKeyValue(key, defaultValue, userId);
    252     }
    253 
    254     @Override
    255     public boolean havePassword(int userId) throws RemoteException {
    256         // Do we need a permissions check here?
    257 
    258         return mStorage.hasPassword(userId);
    259     }
    260 
    261     @Override
    262     public boolean havePattern(int userId) throws RemoteException {
    263         // Do we need a permissions check here?
    264 
    265         return mStorage.hasPattern(userId);
    266     }
    267 
    268     private void maybeUpdateKeystore(String password, int userHandle) {
    269         final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
    270         final KeyStore ks = KeyStore.getInstance();
    271 
    272         final List<UserInfo> profiles = um.getProfiles(userHandle);
    273         boolean shouldReset = TextUtils.isEmpty(password);
    274 
    275         // For historical reasons, don't wipe a non-empty keystore if we have a single user with a
    276         // single profile.
    277         if (userHandle == UserHandle.USER_OWNER && profiles.size() == 1) {
    278             if (!ks.isEmpty()) {
    279                 shouldReset = false;
    280             }
    281         }
    282 
    283         for (UserInfo pi : profiles) {
    284             final int profileUid = UserHandle.getUid(pi.id, Process.SYSTEM_UID);
    285             if (shouldReset) {
    286                 ks.resetUid(profileUid);
    287             } else {
    288                 ks.passwordUid(password, profileUid);
    289             }
    290         }
    291     }
    292 
    293     @Override
    294     public void setLockPattern(String pattern, int userId) throws RemoteException {
    295         checkWritePermission(userId);
    296 
    297         maybeUpdateKeystore(pattern, userId);
    298 
    299         final byte[] hash = LockPatternUtils.patternToHash(
    300                 LockPatternUtils.stringToPattern(pattern));
    301         mStorage.writePatternHash(hash, userId);
    302     }
    303 
    304     @Override
    305     public void setLockPassword(String password, int userId) throws RemoteException {
    306         checkWritePermission(userId);
    307 
    308         maybeUpdateKeystore(password, userId);
    309 
    310         mStorage.writePasswordHash(mLockPatternUtils.passwordToHash(password, userId), userId);
    311     }
    312 
    313     @Override
    314     public boolean checkPattern(String pattern, int userId) throws RemoteException {
    315         checkPasswordReadPermission(userId);
    316         byte[] hash = LockPatternUtils.patternToHash(LockPatternUtils.stringToPattern(pattern));
    317         byte[] storedHash = mStorage.readPatternHash(userId);
    318 
    319         if (storedHash == null) {
    320             return true;
    321         }
    322 
    323         boolean matched = Arrays.equals(hash, storedHash);
    324         if (matched && !TextUtils.isEmpty(pattern)) {
    325             maybeUpdateKeystore(pattern, userId);
    326         }
    327         return matched;
    328     }
    329 
    330     @Override
    331     public boolean checkPassword(String password, int userId) throws RemoteException {
    332         checkPasswordReadPermission(userId);
    333 
    334         byte[] hash = mLockPatternUtils.passwordToHash(password, userId);
    335         byte[] storedHash = mStorage.readPasswordHash(userId);
    336 
    337         if (storedHash == null) {
    338             return true;
    339         }
    340 
    341         boolean matched = Arrays.equals(hash, storedHash);
    342         if (matched && !TextUtils.isEmpty(password)) {
    343             maybeUpdateKeystore(password, userId);
    344         }
    345         return matched;
    346     }
    347 
    348     @Override
    349     public boolean checkVoldPassword(int userId) throws RemoteException {
    350         if (!mFirstCallToVold) {
    351             return false;
    352         }
    353         mFirstCallToVold = false;
    354 
    355         checkPasswordReadPermission(userId);
    356 
    357         // There's no guarantee that this will safely connect, but if it fails
    358         // we will simply show the lock screen when we shouldn't, so relatively
    359         // benign. There is an outside chance something nasty would happen if
    360         // this service restarted before vold stales out the password in this
    361         // case. The nastiness is limited to not showing the lock screen when
    362         // we should, within the first minute of decrypting the phone if this
    363         // service can't connect to vold, it restarts, and then the new instance
    364         // does successfully connect.
    365         final IMountService service = getMountService();
    366         String password = service.getPassword();
    367         service.clearPassword();
    368         if (password == null) {
    369             return false;
    370         }
    371 
    372         try {
    373             if (mLockPatternUtils.isLockPatternEnabled()) {
    374                 if (checkPattern(password, userId)) {
    375                     return true;
    376                 }
    377             }
    378         } catch (Exception e) {
    379         }
    380 
    381         try {
    382             if (mLockPatternUtils.isLockPasswordEnabled()) {
    383                 if (checkPassword(password, userId)) {
    384                     return true;
    385                 }
    386             }
    387         } catch (Exception e) {
    388         }
    389 
    390         return false;
    391     }
    392 
    393     @Override
    394     public void removeUser(int userId) {
    395         checkWritePermission(userId);
    396 
    397         mStorage.removeUser(userId);
    398 
    399         final KeyStore ks = KeyStore.getInstance();
    400         final int userUid = UserHandle.getUid(userId, Process.SYSTEM_UID);
    401         ks.resetUid(userUid);
    402     }
    403 
    404     private static final String[] VALID_SETTINGS = new String[] {
    405         LockPatternUtils.LOCKOUT_PERMANENT_KEY,
    406         LockPatternUtils.LOCKOUT_ATTEMPT_DEADLINE,
    407         LockPatternUtils.PATTERN_EVER_CHOSEN_KEY,
    408         LockPatternUtils.PASSWORD_TYPE_KEY,
    409         LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY,
    410         LockPatternUtils.LOCK_PASSWORD_SALT_KEY,
    411         LockPatternUtils.DISABLE_LOCKSCREEN_KEY,
    412         LockPatternUtils.LOCKSCREEN_OPTIONS,
    413         LockPatternUtils.LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK,
    414         LockPatternUtils.BIOMETRIC_WEAK_EVER_CHOSEN_KEY,
    415         LockPatternUtils.LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS,
    416         LockPatternUtils.PASSWORD_HISTORY_KEY,
    417         Secure.LOCK_PATTERN_ENABLED,
    418         Secure.LOCK_BIOMETRIC_WEAK_FLAGS,
    419         Secure.LOCK_PATTERN_VISIBLE,
    420         Secure.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED
    421     };
    422 
    423     // These are protected with a read permission
    424     private static final String[] READ_PROFILE_PROTECTED_SETTINGS = new String[] {
    425         Secure.LOCK_SCREEN_OWNER_INFO_ENABLED,
    426         Secure.LOCK_SCREEN_OWNER_INFO
    427     };
    428 
    429     private IMountService getMountService() {
    430         final IBinder service = ServiceManager.getService("mount");
    431         if (service != null) {
    432             return IMountService.Stub.asInterface(service);
    433         }
    434         return null;
    435     }
    436 }
    437