LockSettingsService.java revision b5383455b6cae093e60684b4f5cccb0cc440330d
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.app.admin.DevicePolicyManager; 20import android.app.backup.BackupManager; 21import android.content.BroadcastReceiver; 22import android.content.ContentResolver; 23import android.content.Context; 24import android.content.Intent; 25import android.content.IntentFilter; 26import android.content.pm.PackageManager; 27import android.content.pm.UserInfo; 28import static android.Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE; 29import static android.content.Context.USER_SERVICE; 30import static android.Manifest.permission.READ_CONTACTS; 31import android.database.sqlite.SQLiteDatabase; 32import android.os.Binder; 33import android.os.IBinder; 34import android.os.RemoteException; 35import android.os.storage.IMountService; 36import android.os.ServiceManager; 37import android.os.SystemProperties; 38import android.os.UserHandle; 39import android.os.UserManager; 40import android.provider.Settings; 41import android.provider.Settings.Secure; 42import android.provider.Settings.SettingNotFoundException; 43import android.security.KeyStore; 44import android.service.gatekeeper.GateKeeperResponse; 45import android.service.gatekeeper.IGateKeeperService; 46import android.text.TextUtils; 47import android.util.Slog; 48 49import com.android.internal.util.ArrayUtils; 50import com.android.internal.widget.ILockSettings; 51import com.android.internal.widget.LockPatternUtils; 52import com.android.internal.widget.VerifyCredentialResponse; 53import com.android.server.LockSettingsStorage.CredentialHash; 54 55import java.util.Arrays; 56import java.util.List; 57 58/** 59 * Keeps the lock pattern/password data and related settings for each user. 60 * Used by LockPatternUtils. Needs to be a service because Settings app also needs 61 * to be able to save lockscreen information for secondary users. 62 * @hide 63 */ 64public class LockSettingsService extends ILockSettings.Stub { 65 66 private static final String PERMISSION = ACCESS_KEYGUARD_SECURE_STORAGE; 67 68 private static final String TAG = "LockSettingsService"; 69 70 private final Context mContext; 71 72 private final LockSettingsStorage mStorage; 73 74 private LockPatternUtils mLockPatternUtils; 75 private boolean mFirstCallToVold; 76 private IGateKeeperService mGateKeeperService; 77 78 private interface CredentialUtil { 79 void setCredential(String credential, String savedCredential, int userId) 80 throws RemoteException; 81 byte[] toHash(String credential, int userId); 82 String adjustForKeystore(String credential); 83 } 84 85 public LockSettingsService(Context context) { 86 mContext = context; 87 // Open the database 88 89 mLockPatternUtils = new LockPatternUtils(context); 90 mFirstCallToVold = true; 91 92 IntentFilter filter = new IntentFilter(); 93 filter.addAction(Intent.ACTION_USER_ADDED); 94 filter.addAction(Intent.ACTION_USER_STARTING); 95 filter.addAction(Intent.ACTION_USER_REMOVED); 96 mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null); 97 98 mStorage = new LockSettingsStorage(context, new LockSettingsStorage.Callback() { 99 @Override 100 public void initialize(SQLiteDatabase db) { 101 // Get the lockscreen default from a system property, if available 102 boolean lockScreenDisable = SystemProperties.getBoolean( 103 "ro.lockscreen.disable.default", false); 104 if (lockScreenDisable) { 105 mStorage.writeKeyValue(db, LockPatternUtils.DISABLE_LOCKSCREEN_KEY, "1", 0); 106 } 107 } 108 }); 109 } 110 111 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 112 @Override 113 public void onReceive(Context context, Intent intent) { 114 if (Intent.ACTION_USER_ADDED.equals(intent.getAction())) { 115 // Notify keystore that a new user was added. 116 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0); 117 final KeyStore ks = KeyStore.getInstance(); 118 final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE); 119 final UserInfo parentInfo = um.getProfileParent(userHandle); 120 final int parentHandle = parentInfo != null ? parentInfo.id : -1; 121 ks.onUserAdded(userHandle, parentHandle); 122 } else if (Intent.ACTION_USER_STARTING.equals(intent.getAction())) { 123 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0); 124 mStorage.prefetchUser(userHandle); 125 } else if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) { 126 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0); 127 if (userHandle > 0) { 128 removeUser(userHandle); 129 } 130 } 131 } 132 }; 133 134 public void systemReady() { 135 migrateOldData(); 136 try { 137 getGateKeeperService(); 138 } catch (RemoteException e) { 139 Slog.e(TAG, "Failure retrieving IGateKeeperService", e); 140 } 141 mStorage.prefetchUser(UserHandle.USER_OWNER); 142 } 143 144 private void migrateOldData() { 145 try { 146 // These Settings moved before multi-user was enabled, so we only have to do it for the 147 // root user. 148 if (getString("migrated", null, 0) == null) { 149 final ContentResolver cr = mContext.getContentResolver(); 150 for (String validSetting : VALID_SETTINGS) { 151 String value = Settings.Secure.getString(cr, validSetting); 152 if (value != null) { 153 setString(validSetting, value, 0); 154 } 155 } 156 // No need to move the password / pattern files. They're already in the right place. 157 setString("migrated", "true", 0); 158 Slog.i(TAG, "Migrated lock settings to new location"); 159 } 160 161 // These Settings changed after multi-user was enabled, hence need to be moved per user. 162 if (getString("migrated_user_specific", null, 0) == null) { 163 final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE); 164 final ContentResolver cr = mContext.getContentResolver(); 165 List<UserInfo> users = um.getUsers(); 166 for (int user = 0; user < users.size(); user++) { 167 // Migrate owner info 168 final int userId = users.get(user).id; 169 final String OWNER_INFO = Secure.LOCK_SCREEN_OWNER_INFO; 170 String ownerInfo = Settings.Secure.getStringForUser(cr, OWNER_INFO, userId); 171 if (ownerInfo != null) { 172 setString(OWNER_INFO, ownerInfo, userId); 173 Settings.Secure.putStringForUser(cr, ownerInfo, "", userId); 174 } 175 176 // Migrate owner info enabled. Note there was a bug where older platforms only 177 // stored this value if the checkbox was toggled at least once. The code detects 178 // this case by handling the exception. 179 final String OWNER_INFO_ENABLED = Secure.LOCK_SCREEN_OWNER_INFO_ENABLED; 180 boolean enabled; 181 try { 182 int ivalue = Settings.Secure.getIntForUser(cr, OWNER_INFO_ENABLED, userId); 183 enabled = ivalue != 0; 184 setLong(OWNER_INFO_ENABLED, enabled ? 1 : 0, userId); 185 } catch (SettingNotFoundException e) { 186 // Setting was never stored. Store it if the string is not empty. 187 if (!TextUtils.isEmpty(ownerInfo)) { 188 setLong(OWNER_INFO_ENABLED, 1, userId); 189 } 190 } 191 Settings.Secure.putIntForUser(cr, OWNER_INFO_ENABLED, 0, userId); 192 } 193 // No need to move the password / pattern files. They're already in the right place. 194 setString("migrated_user_specific", "true", 0); 195 Slog.i(TAG, "Migrated per-user lock settings to new location"); 196 } 197 198 // Migrates biometric weak such that the fallback mechanism becomes the primary. 199 if (getString("migrated_biometric_weak", null, 0) == null) { 200 final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE); 201 List<UserInfo> users = um.getUsers(); 202 for (int i = 0; i < users.size(); i++) { 203 int userId = users.get(i).id; 204 long type = getLong(LockPatternUtils.PASSWORD_TYPE_KEY, 205 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 206 userId); 207 long alternateType = getLong(LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY, 208 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 209 userId); 210 if (type == DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK) { 211 setLong(LockPatternUtils.PASSWORD_TYPE_KEY, 212 alternateType, 213 userId); 214 } 215 setLong(LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY, 216 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 217 userId); 218 } 219 setString("migrated_biometric_weak", "true", 0); 220 Slog.i(TAG, "Migrated biometric weak to use the fallback instead"); 221 } 222 223 // Migrates lockscreen.disabled. Prior to M, the flag was ignored when more than one 224 // user was present on the system, so if we're upgrading to M and there is more than one 225 // user we disable the flag to remain consistent. 226 if (getString("migrated_lockscreen_disabled", null, 0) == null) { 227 final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE); 228 229 final List<UserInfo> users = um.getUsers(); 230 final int userCount = users.size(); 231 int switchableUsers = 0; 232 for (int i = 0; i < userCount; i++) { 233 if (users.get(i).supportsSwitchTo()) { 234 switchableUsers++; 235 } 236 } 237 238 if (switchableUsers > 1) { 239 for (int i = 0; i < userCount; i++) { 240 int id = users.get(i).id; 241 242 if (getBoolean(LockPatternUtils.DISABLE_LOCKSCREEN_KEY, false, id)) { 243 setBoolean(LockPatternUtils.DISABLE_LOCKSCREEN_KEY, false, id); 244 } 245 } 246 } 247 248 setString("migrated_lockscreen_disabled", "true", 0); 249 Slog.i(TAG, "Migrated lockscreen disabled flag"); 250 } 251 } catch (RemoteException re) { 252 Slog.e(TAG, "Unable to migrate old data", re); 253 } 254 } 255 256 private final void checkWritePermission(int userId) { 257 mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsWrite"); 258 } 259 260 private final void checkPasswordReadPermission(int userId) { 261 mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsRead"); 262 } 263 264 private final void checkReadPermission(String requestedKey, int userId) { 265 final int callingUid = Binder.getCallingUid(); 266 267 for (int i = 0; i < READ_CONTACTS_PROTECTED_SETTINGS.length; i++) { 268 String key = READ_CONTACTS_PROTECTED_SETTINGS[i]; 269 if (key.equals(requestedKey) && mContext.checkCallingOrSelfPermission(READ_CONTACTS) 270 != PackageManager.PERMISSION_GRANTED) { 271 throw new SecurityException("uid=" + callingUid 272 + " needs permission " + READ_CONTACTS + " to read " 273 + requestedKey + " for user " + userId); 274 } 275 } 276 277 for (int i = 0; i < READ_PASSWORD_PROTECTED_SETTINGS.length; i++) { 278 String key = READ_PASSWORD_PROTECTED_SETTINGS[i]; 279 if (key.equals(requestedKey) && mContext.checkCallingOrSelfPermission(PERMISSION) 280 != PackageManager.PERMISSION_GRANTED) { 281 throw new SecurityException("uid=" + callingUid 282 + " needs permission " + PERMISSION + " to read " 283 + requestedKey + " for user " + userId); 284 } 285 } 286 } 287 288 @Override 289 public void setBoolean(String key, boolean value, int userId) throws RemoteException { 290 checkWritePermission(userId); 291 setStringUnchecked(key, userId, value ? "1" : "0"); 292 } 293 294 @Override 295 public void setLong(String key, long value, int userId) throws RemoteException { 296 checkWritePermission(userId); 297 setStringUnchecked(key, userId, Long.toString(value)); 298 } 299 300 @Override 301 public void setString(String key, String value, int userId) throws RemoteException { 302 checkWritePermission(userId); 303 setStringUnchecked(key, userId, value); 304 } 305 306 private void setStringUnchecked(String key, int userId, String value) { 307 mStorage.writeKeyValue(key, value, userId); 308 if (ArrayUtils.contains(SETTINGS_TO_BACKUP, key)) { 309 BackupManager.dataChanged("com.android.providers.settings"); 310 } 311 } 312 313 @Override 314 public boolean getBoolean(String key, boolean defaultValue, int userId) throws RemoteException { 315 checkReadPermission(key, userId); 316 String value = getStringUnchecked(key, null, userId); 317 return TextUtils.isEmpty(value) ? 318 defaultValue : (value.equals("1") || value.equals("true")); 319 } 320 321 @Override 322 public long getLong(String key, long defaultValue, int userId) throws RemoteException { 323 checkReadPermission(key, userId); 324 325 String value = getStringUnchecked(key, null, userId); 326 return TextUtils.isEmpty(value) ? defaultValue : Long.parseLong(value); 327 } 328 329 @Override 330 public String getString(String key, String defaultValue, int userId) throws RemoteException { 331 checkReadPermission(key, userId); 332 333 return getStringUnchecked(key, defaultValue, userId); 334 } 335 336 public String getStringUnchecked(String key, String defaultValue, int userId) { 337 if (Settings.Secure.LOCK_PATTERN_ENABLED.equals(key)) { 338 long ident = Binder.clearCallingIdentity(); 339 try { 340 return mLockPatternUtils.isLockPatternEnabled(userId) ? "1" : "0"; 341 } finally { 342 Binder.restoreCallingIdentity(ident); 343 } 344 } 345 346 return mStorage.readKeyValue(key, defaultValue, userId); 347 } 348 349 @Override 350 public boolean havePassword(int userId) throws RemoteException { 351 // Do we need a permissions check here? 352 353 return mStorage.hasPassword(userId); 354 } 355 356 @Override 357 public boolean havePattern(int userId) throws RemoteException { 358 // Do we need a permissions check here? 359 360 return mStorage.hasPattern(userId); 361 } 362 363 private void setKeystorePassword(String password, int userHandle) { 364 final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE); 365 final KeyStore ks = KeyStore.getInstance(); 366 367 final List<UserInfo> profiles = um.getProfiles(userHandle); 368 for (UserInfo pi : profiles) { 369 ks.onUserPasswordChanged(pi.id, password); 370 } 371 } 372 373 private void unlockKeystore(String password, int userHandle) { 374 final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE); 375 final KeyStore ks = KeyStore.getInstance(); 376 377 final List<UserInfo> profiles = um.getProfiles(userHandle); 378 for (UserInfo pi : profiles) { 379 ks.unlock(pi.id, password); 380 } 381 } 382 383 384 private byte[] getCurrentHandle(int userId) { 385 CredentialHash credential; 386 byte[] currentHandle; 387 388 int currentHandleType = mStorage.getStoredCredentialType(userId); 389 switch (currentHandleType) { 390 case CredentialHash.TYPE_PATTERN: 391 credential = mStorage.readPatternHash(userId); 392 currentHandle = credential != null 393 ? credential.hash 394 : null; 395 break; 396 case CredentialHash.TYPE_PASSWORD: 397 credential = mStorage.readPasswordHash(userId); 398 currentHandle = credential != null 399 ? credential.hash 400 : null; 401 break; 402 case CredentialHash.TYPE_NONE: 403 default: 404 currentHandle = null; 405 break; 406 } 407 408 // sanity check 409 if (currentHandleType != CredentialHash.TYPE_NONE && currentHandle == null) { 410 Slog.e(TAG, "Stored handle type [" + currentHandleType + "] but no handle available"); 411 } 412 413 return currentHandle; 414 } 415 416 417 @Override 418 public void setLockPattern(String pattern, String savedCredential, int userId) 419 throws RemoteException { 420 checkWritePermission(userId); 421 byte[] currentHandle = getCurrentHandle(userId); 422 423 if (pattern == null) { 424 getGateKeeperService().clearSecureUserId(userId); 425 mStorage.writePatternHash(null, userId); 426 setKeystorePassword(null, userId); 427 return; 428 } 429 430 if (currentHandle == null) { 431 if (savedCredential != null) { 432 Slog.w(TAG, "Saved credential provided, but none stored"); 433 } 434 savedCredential = null; 435 } 436 437 byte[] enrolledHandle = enrollCredential(currentHandle, savedCredential, pattern, userId); 438 if (enrolledHandle != null) { 439 mStorage.writePatternHash(enrolledHandle, userId); 440 } else { 441 Slog.e(TAG, "Failed to enroll pattern"); 442 } 443 } 444 445 446 @Override 447 public void setLockPassword(String password, String savedCredential, int userId) 448 throws RemoteException { 449 checkWritePermission(userId); 450 byte[] currentHandle = getCurrentHandle(userId); 451 452 if (password == null) { 453 getGateKeeperService().clearSecureUserId(userId); 454 mStorage.writePasswordHash(null, userId); 455 setKeystorePassword(null, userId); 456 return; 457 } 458 459 if (currentHandle == null) { 460 if (savedCredential != null) { 461 Slog.w(TAG, "Saved credential provided, but none stored"); 462 } 463 savedCredential = null; 464 } 465 466 byte[] enrolledHandle = enrollCredential(currentHandle, savedCredential, password, userId); 467 if (enrolledHandle != null) { 468 mStorage.writePasswordHash(enrolledHandle, userId); 469 } else { 470 Slog.e(TAG, "Failed to enroll password"); 471 } 472 } 473 474 private byte[] enrollCredential(byte[] enrolledHandle, 475 String enrolledCredential, String toEnroll, int userId) 476 throws RemoteException { 477 checkWritePermission(userId); 478 byte[] enrolledCredentialBytes = enrolledCredential == null 479 ? null 480 : enrolledCredential.getBytes(); 481 byte[] toEnrollBytes = toEnroll == null 482 ? null 483 : toEnroll.getBytes(); 484 GateKeeperResponse response = getGateKeeperService().enroll(userId, enrolledHandle, 485 enrolledCredentialBytes, toEnrollBytes); 486 487 if (response == null) { 488 return null; 489 } 490 491 byte[] hash = response.getPayload(); 492 if (hash != null) { 493 setKeystorePassword(toEnroll, userId); 494 } else { 495 // Should not happen 496 Slog.e(TAG, "Throttled while enrolling a password"); 497 } 498 return hash; 499 } 500 501 @Override 502 public VerifyCredentialResponse checkPattern(String pattern, int userId) throws RemoteException { 503 return doVerifyPattern(pattern, false, 0, userId); 504 } 505 506 @Override 507 public VerifyCredentialResponse verifyPattern(String pattern, long challenge, int userId) 508 throws RemoteException { 509 return doVerifyPattern(pattern, true, challenge, userId); 510 } 511 512 private VerifyCredentialResponse doVerifyPattern(String pattern, boolean hasChallenge, 513 long challenge, int userId) throws RemoteException { 514 checkPasswordReadPermission(userId); 515 CredentialHash storedHash = mStorage.readPatternHash(userId); 516 boolean shouldReEnrollBaseZero = storedHash != null && storedHash.isBaseZeroPattern; 517 518 String patternToVerify; 519 if (shouldReEnrollBaseZero) { 520 patternToVerify = LockPatternUtils.patternStringToBaseZero(pattern); 521 } else { 522 patternToVerify = pattern; 523 } 524 525 VerifyCredentialResponse response = verifyCredential(userId, storedHash, patternToVerify, 526 hasChallenge, challenge, 527 new CredentialUtil() { 528 @Override 529 public void setCredential(String pattern, String oldPattern, int userId) 530 throws RemoteException { 531 setLockPattern(pattern, oldPattern, userId); 532 } 533 534 @Override 535 public byte[] toHash(String pattern, int userId) { 536 return LockPatternUtils.patternToHash( 537 LockPatternUtils.stringToPattern(pattern)); 538 } 539 540 @Override 541 public String adjustForKeystore(String pattern) { 542 return LockPatternUtils.patternStringToBaseZero(pattern); 543 } 544 } 545 ); 546 547 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK 548 && shouldReEnrollBaseZero) { 549 setLockPattern(pattern, patternToVerify, userId); 550 } 551 552 return response; 553 554 } 555 556 @Override 557 public VerifyCredentialResponse checkPassword(String password, int userId) 558 throws RemoteException { 559 return doVerifyPassword(password, false, 0, userId); 560 } 561 562 @Override 563 public VerifyCredentialResponse verifyPassword(String password, long challenge, int userId) 564 throws RemoteException { 565 return doVerifyPassword(password, true, challenge, userId); 566 } 567 568 private VerifyCredentialResponse doVerifyPassword(String password, boolean hasChallenge, 569 long challenge, int userId) throws RemoteException { 570 checkPasswordReadPermission(userId); 571 CredentialHash storedHash = mStorage.readPasswordHash(userId); 572 return verifyCredential(userId, storedHash, password, hasChallenge, challenge, 573 new CredentialUtil() { 574 @Override 575 public void setCredential(String password, String oldPassword, int userId) 576 throws RemoteException { 577 setLockPassword(password, oldPassword, userId); 578 } 579 580 @Override 581 public byte[] toHash(String password, int userId) { 582 return mLockPatternUtils.passwordToHash(password, userId); 583 } 584 585 @Override 586 public String adjustForKeystore(String password) { 587 return password; 588 } 589 } 590 ); 591 } 592 593 private VerifyCredentialResponse verifyCredential(int userId, CredentialHash storedHash, 594 String credential, boolean hasChallenge, long challenge, CredentialUtil credentialUtil) 595 throws RemoteException { 596 if ((storedHash == null || storedHash.hash.length == 0) && TextUtils.isEmpty(credential)) { 597 // don't need to pass empty credentials to GateKeeper 598 return VerifyCredentialResponse.OK; 599 } 600 601 if (TextUtils.isEmpty(credential)) { 602 return VerifyCredentialResponse.ERROR; 603 } 604 605 if (storedHash.version == CredentialHash.VERSION_LEGACY) { 606 byte[] hash = credentialUtil.toHash(credential, userId); 607 if (Arrays.equals(hash, storedHash.hash)) { 608 unlockKeystore(credentialUtil.adjustForKeystore(credential), userId); 609 // migrate credential to GateKeeper 610 credentialUtil.setCredential(credential, null, userId); 611 if (!hasChallenge) { 612 return VerifyCredentialResponse.OK; 613 } 614 // Fall through to get the auth token. Technically this should never happen, 615 // as a user that had a legacy credential would have to unlock their device 616 // before getting to a flow with a challenge, but supporting for consistency. 617 } else { 618 return VerifyCredentialResponse.ERROR; 619 } 620 } 621 622 VerifyCredentialResponse response; 623 boolean shouldReEnroll = false;; 624 if (hasChallenge) { 625 byte[] token = null; 626 GateKeeperResponse gateKeeperResponse = getGateKeeperService() 627 .verifyChallenge(userId, challenge, storedHash.hash, credential.getBytes()); 628 int responseCode = gateKeeperResponse.getResponseCode(); 629 if (responseCode == GateKeeperResponse.RESPONSE_RETRY) { 630 response = new VerifyCredentialResponse(gateKeeperResponse.getTimeout()); 631 } else if (responseCode == GateKeeperResponse.RESPONSE_OK) { 632 token = gateKeeperResponse.getPayload(); 633 if (token == null) { 634 // something's wrong if there's no payload with a challenge 635 Slog.e(TAG, "verifyChallenge response had no associated payload"); 636 response = VerifyCredentialResponse.ERROR; 637 } else { 638 shouldReEnroll = gateKeeperResponse.getShouldReEnroll(); 639 response = new VerifyCredentialResponse(token); 640 } 641 } else { 642 response = VerifyCredentialResponse.ERROR; 643 } 644 } else { 645 GateKeeperResponse gateKeeperResponse = getGateKeeperService().verify( 646 userId, storedHash.hash, credential.getBytes()); 647 int responseCode = gateKeeperResponse.getResponseCode(); 648 if (responseCode == GateKeeperResponse.RESPONSE_RETRY) { 649 response = new VerifyCredentialResponse(gateKeeperResponse.getTimeout()); 650 } else if (responseCode == GateKeeperResponse.RESPONSE_OK) { 651 shouldReEnroll = gateKeeperResponse.getShouldReEnroll(); 652 response = VerifyCredentialResponse.OK; 653 } else { 654 response = VerifyCredentialResponse.ERROR; 655 } 656 } 657 658 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) { 659 // credential has matched 660 unlockKeystore(credential, userId); 661 if (shouldReEnroll) { 662 credentialUtil.setCredential(credential, credential, userId); 663 } 664 } 665 666 return response; 667 } 668 669 @Override 670 public boolean checkVoldPassword(int userId) throws RemoteException { 671 if (!mFirstCallToVold) { 672 return false; 673 } 674 mFirstCallToVold = false; 675 676 checkPasswordReadPermission(userId); 677 678 // There's no guarantee that this will safely connect, but if it fails 679 // we will simply show the lock screen when we shouldn't, so relatively 680 // benign. There is an outside chance something nasty would happen if 681 // this service restarted before vold stales out the password in this 682 // case. The nastiness is limited to not showing the lock screen when 683 // we should, within the first minute of decrypting the phone if this 684 // service can't connect to vold, it restarts, and then the new instance 685 // does successfully connect. 686 final IMountService service = getMountService(); 687 String password = service.getPassword(); 688 service.clearPassword(); 689 if (password == null) { 690 return false; 691 } 692 693 try { 694 if (mLockPatternUtils.isLockPatternEnabled(userId)) { 695 if (checkPattern(password, userId).getResponseCode() 696 == GateKeeperResponse.RESPONSE_OK) { 697 return true; 698 } 699 } 700 } catch (Exception e) { 701 } 702 703 try { 704 if (mLockPatternUtils.isLockPasswordEnabled(userId)) { 705 if (checkPassword(password, userId).getResponseCode() 706 == GateKeeperResponse.RESPONSE_OK) { 707 return true; 708 } 709 } 710 } catch (Exception e) { 711 } 712 713 return false; 714 } 715 716 private void removeUser(int userId) { 717 mStorage.removeUser(userId); 718 719 final KeyStore ks = KeyStore.getInstance(); 720 ks.onUserRemoved(userId); 721 722 try { 723 final IGateKeeperService gk = getGateKeeperService(); 724 if (gk != null) { 725 gk.clearSecureUserId(userId); 726 } 727 } catch (RemoteException ex) { 728 Slog.w(TAG, "unable to clear GK secure user id"); 729 } 730 } 731 732 private static final String[] VALID_SETTINGS = new String[] { 733 LockPatternUtils.LOCKOUT_PERMANENT_KEY, 734 LockPatternUtils.LOCKOUT_ATTEMPT_DEADLINE, 735 LockPatternUtils.PATTERN_EVER_CHOSEN_KEY, 736 LockPatternUtils.PASSWORD_TYPE_KEY, 737 LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY, 738 LockPatternUtils.LOCK_PASSWORD_SALT_KEY, 739 LockPatternUtils.DISABLE_LOCKSCREEN_KEY, 740 LockPatternUtils.LOCKSCREEN_OPTIONS, 741 LockPatternUtils.LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK, 742 LockPatternUtils.BIOMETRIC_WEAK_EVER_CHOSEN_KEY, 743 LockPatternUtils.LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, 744 LockPatternUtils.PASSWORD_HISTORY_KEY, 745 Secure.LOCK_PATTERN_ENABLED, 746 Secure.LOCK_BIOMETRIC_WEAK_FLAGS, 747 Secure.LOCK_PATTERN_VISIBLE, 748 Secure.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED 749 }; 750 751 // Reading these settings needs the contacts permission 752 private static final String[] READ_CONTACTS_PROTECTED_SETTINGS = new String[] { 753 Secure.LOCK_SCREEN_OWNER_INFO_ENABLED, 754 Secure.LOCK_SCREEN_OWNER_INFO 755 }; 756 757 // Reading these settings needs the same permission as checking the password 758 private static final String[] READ_PASSWORD_PROTECTED_SETTINGS = new String[] { 759 LockPatternUtils.LOCK_PASSWORD_SALT_KEY, 760 LockPatternUtils.PASSWORD_HISTORY_KEY, 761 LockPatternUtils.PASSWORD_TYPE_KEY, 762 }; 763 764 private static final String[] SETTINGS_TO_BACKUP = new String[] { 765 Secure.LOCK_SCREEN_OWNER_INFO_ENABLED, 766 Secure.LOCK_SCREEN_OWNER_INFO 767 }; 768 769 private IMountService getMountService() { 770 final IBinder service = ServiceManager.getService("mount"); 771 if (service != null) { 772 return IMountService.Stub.asInterface(service); 773 } 774 return null; 775 } 776 777 private class GateKeeperDiedRecipient implements IBinder.DeathRecipient { 778 @Override 779 public void binderDied() { 780 mGateKeeperService.asBinder().unlinkToDeath(this, 0); 781 mGateKeeperService = null; 782 } 783 } 784 785 private synchronized IGateKeeperService getGateKeeperService() 786 throws RemoteException { 787 if (mGateKeeperService != null) { 788 return mGateKeeperService; 789 } 790 791 final IBinder service = 792 ServiceManager.getService("android.service.gatekeeper.IGateKeeperService"); 793 if (service != null) { 794 service.linkToDeath(new GateKeeperDiedRecipient(), 0); 795 mGateKeeperService = IGateKeeperService.Stub.asInterface(service); 796 return mGateKeeperService; 797 } 798 799 Slog.e(TAG, "Unable to acquire GateKeeperService"); 800 return null; 801 } 802 803} 804