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 17package com.android.server; 18 19import android.content.BroadcastReceiver; 20import android.content.ContentResolver; 21import android.content.Context; 22import android.content.Intent; 23import android.content.IntentFilter; 24import android.content.pm.PackageManager; 25import android.content.pm.UserInfo; 26 27import static android.Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE; 28import static android.content.Context.USER_SERVICE; 29import static android.Manifest.permission.READ_PROFILE; 30 31import android.database.sqlite.SQLiteDatabase; 32import android.os.Binder; 33import android.os.IBinder; 34import android.os.Process; 35import android.os.RemoteException; 36import android.os.storage.IMountService; 37import android.os.ServiceManager; 38import android.os.SystemProperties; 39import android.os.UserHandle; 40import android.os.UserManager; 41import android.provider.Settings; 42import android.provider.Settings.Secure; 43import android.provider.Settings.SettingNotFoundException; 44import android.security.KeyStore; 45import android.text.TextUtils; 46import android.util.Slog; 47 48import com.android.internal.widget.ILockSettings; 49import com.android.internal.widget.LockPatternUtils; 50 51import java.util.ArrayList; 52import java.util.Arrays; 53import 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 */ 61public 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