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