2 * Copyright (C) 2012 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.server;
19 import android.app.ActivityManagerNative;
20 import android.app.Notification;
21 import android.app.NotificationManager;
22 import android.app.PendingIntent;
23 import android.app.admin.DevicePolicyManager;
24 import android.app.backup.BackupManager;
25 import android.app.trust.IStrongAuthTracker;
26 import android.app.trust.TrustManager;
27 import android.content.BroadcastReceiver;
28 import android.content.ContentResolver;
29 import android.content.Context;
30 import android.content.Intent;
31 import android.content.IntentFilter;
32 import android.content.pm.PackageManager;
33 import android.content.pm.UserInfo;
34 import android.content.res.Resources;
36 import static android.Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE;
37 import static android.content.Context.USER_SERVICE;
38 import static android.Manifest.permission.READ_CONTACTS;
39 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
41 import android.database.sqlite.SQLiteDatabase;
42 import android.os.Binder;
43 import android.os.IBinder;
44 import android.os.RemoteException;
45 import android.os.storage.IMountService;
46 import android.os.ServiceManager;
47 import android.os.SystemProperties;
48 import android.os.UserHandle;
49 import android.os.UserManager;
50 import android.provider.Settings;
51 import android.provider.Settings.Secure;
52 import android.provider.Settings.SettingNotFoundException;
53 import android.security.KeyStore;
54 import android.service.gatekeeper.GateKeeperResponse;
55 import android.service.gatekeeper.IGateKeeperService;
56 import android.text.TextUtils;
57 import android.util.Slog;
59 import com.android.internal.util.ArrayUtils;
60 import com.android.internal.widget.ILockSettings;
61 import com.android.internal.widget.LockPatternUtils;
62 import com.android.internal.widget.VerifyCredentialResponse;
63 import com.android.server.LockSettingsStorage.CredentialHash;
65 import java.util.Arrays;
66 import java.util.List;
69 * Keeps the lock pattern/password data and related settings for each user.
70 * Used by LockPatternUtils. Needs to be a service because Settings app also needs
71 * to be able to save lockscreen information for secondary users.
74 public class LockSettingsService extends ILockSettings.Stub {
75 private static final String TAG = "LockSettingsService";
76 private static final String PERMISSION = ACCESS_KEYGUARD_SECURE_STORAGE;
77 private static final Intent ACTION_NULL; // hack to ensure notification shows the bouncer
78 private static final int FBE_ENCRYPTED_NOTIFICATION = 0;
79 private static final boolean DEBUG = false;
81 private final Context mContext;
82 private final LockSettingsStorage mStorage;
83 private final LockSettingsStrongAuth mStrongAuth;
85 private LockPatternUtils mLockPatternUtils;
86 private boolean mFirstCallToVold;
87 private IGateKeeperService mGateKeeperService;
88 private NotificationManager mNotificationManager;
89 private UserManager mUserManager;
92 // Just launch the home screen, which happens anyway
93 ACTION_NULL = new Intent(Intent.ACTION_MAIN);
94 ACTION_NULL.addCategory(Intent.CATEGORY_HOME);
97 private interface CredentialUtil {
98 void setCredential(String credential, String savedCredential, int userId)
99 throws RemoteException;
100 byte[] toHash(String credential, int userId);
101 String adjustForKeystore(String credential);
104 // This class manages life cycle events for encrypted users on File Based Encryption (FBE)
105 // devices. The most basic of these is to show/hide notifications about missing features until
106 // the user unlocks the account and credential-encrypted storage is available.
107 public static final class Lifecycle extends SystemService {
108 private LockSettingsService mLockSettingsService;
110 public Lifecycle(Context context) {
115 public void onStart() {
116 mLockSettingsService = new LockSettingsService(getContext());
117 publishBinderService("lock_settings", mLockSettingsService);
121 public void onBootPhase(int phase) {
122 if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
123 mLockSettingsService.maybeShowEncryptionNotification(UserHandle.ALL);
124 } else if (phase == SystemService.PHASE_BOOT_COMPLETED) {
130 public void onUnlockUser(int userHandle) {
131 mLockSettingsService.onUnlockUser(userHandle);
135 public void onCleanupUser(int userHandle) {
136 mLockSettingsService.onCleanupUser(userHandle);
140 public LockSettingsService(Context context) {
142 mStrongAuth = new LockSettingsStrongAuth(context);
145 mLockPatternUtils = new LockPatternUtils(context);
146 mFirstCallToVold = true;
148 IntentFilter filter = new IntentFilter();
149 filter.addAction(Intent.ACTION_USER_ADDED);
150 filter.addAction(Intent.ACTION_USER_STARTING);
151 filter.addAction(Intent.ACTION_USER_REMOVED);
152 filter.addAction(Intent.ACTION_USER_PRESENT);
153 mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
155 mStorage = new LockSettingsStorage(context, new LockSettingsStorage.Callback() {
157 public void initialize(SQLiteDatabase db) {
158 // Get the lockscreen default from a system property, if available
159 boolean lockScreenDisable = SystemProperties.getBoolean(
160 "ro.lockscreen.disable.default", false);
161 if (lockScreenDisable) {
162 mStorage.writeKeyValue(db, LockPatternUtils.DISABLE_LOCKSCREEN_KEY, "1", 0);
166 mNotificationManager = (NotificationManager)
167 mContext.getSystemService(Context.NOTIFICATION_SERVICE);
168 mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
172 * If the account is credential-encrypted, show notification requesting the user to unlock
175 private void maybeShowEncryptionNotification(UserHandle userHandle) {
176 if (UserHandle.ALL.equals(userHandle)) {
177 final List<UserInfo> users = mUserManager.getUsers();
178 for (int i = 0; i < users.size(); i++) {
179 UserHandle user = users.get(i).getUserHandle();
180 if (!mUserManager.isUserUnlocked(user)) {
181 showEncryptionNotification(user);
184 } else if (!mUserManager.isUserUnlocked(userHandle)){
185 showEncryptionNotification(userHandle);
189 private void showEncryptionNotification(UserHandle user) {
190 if (DEBUG) Slog.v(TAG, "showing encryption notification, user: " + user.getIdentifier());
191 Resources r = mContext.getResources();
192 CharSequence title = r.getText(
193 com.android.internal.R.string.user_encrypted_title);
194 CharSequence message = r.getText(
195 com.android.internal.R.string.user_encrypted_message);
196 CharSequence detail = r.getText(
197 com.android.internal.R.string.user_encrypted_detail);
199 PendingIntent intent = PendingIntent.getBroadcast(mContext, 0, ACTION_NULL,
200 PendingIntent.FLAG_UPDATE_CURRENT);
202 Notification notification = new Notification.Builder(mContext)
203 .setSmallIcon(com.android.internal.R.drawable.ic_secure)
207 .setDefaults(0) // please be quiet
208 .setPriority(Notification.PRIORITY_MAX)
209 .setColor(mContext.getColor(
210 com.android.internal.R.color.system_notification_accent_color))
211 .setContentTitle(title)
212 .setContentText(message)
213 .setContentInfo(detail)
214 .setVisibility(Notification.VISIBILITY_PUBLIC)
215 .setContentIntent(intent)
217 mNotificationManager.notifyAsUser(null, FBE_ENCRYPTED_NOTIFICATION, notification, user);
220 public void hideEncryptionNotification(UserHandle userHandle) {
221 if (DEBUG) Slog.v(TAG, "hide encryption notification, user: "+ userHandle.getIdentifier());
222 mNotificationManager.cancelAsUser(null, FBE_ENCRYPTED_NOTIFICATION, userHandle);
225 public void onCleanupUser(int userId) {
226 hideEncryptionNotification(new UserHandle(userId));
229 public void onUnlockUser(int userHandle) {
230 hideEncryptionNotification(new UserHandle(userHandle));
233 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
235 public void onReceive(Context context, Intent intent) {
236 if (Intent.ACTION_USER_ADDED.equals(intent.getAction())) {
237 // Notify keystore that a new user was added.
238 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
239 final KeyStore ks = KeyStore.getInstance();
240 final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
241 final UserInfo parentInfo = um.getProfileParent(userHandle);
242 final int parentHandle = parentInfo != null ? parentInfo.id : -1;
243 ks.onUserAdded(userHandle, parentHandle);
244 } else if (Intent.ACTION_USER_STARTING.equals(intent.getAction())) {
245 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
246 mStorage.prefetchUser(userHandle);
247 } else if (Intent.ACTION_USER_PRESENT.equals(intent.getAction())) {
248 mStrongAuth.reportUnlock(getSendingUserId());
249 } else if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
250 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
251 if (userHandle > 0) {
252 removeUser(userHandle);
258 @Override // binder interface
259 public void systemReady() {
262 getGateKeeperService();
263 } catch (RemoteException e) {
264 Slog.e(TAG, "Failure retrieving IGateKeeperService", e);
266 // TODO: maybe skip this for split system user mode.
267 mStorage.prefetchUser(UserHandle.USER_SYSTEM);
270 private void migrateOldData() {
272 // These Settings moved before multi-user was enabled, so we only have to do it for the
274 if (getString("migrated", null, 0) == null) {
275 final ContentResolver cr = mContext.getContentResolver();
276 for (String validSetting : VALID_SETTINGS) {
277 String value = Settings.Secure.getString(cr, validSetting);
279 setString(validSetting, value, 0);
282 // No need to move the password / pattern files. They're already in the right place.
283 setString("migrated", "true", 0);
284 Slog.i(TAG, "Migrated lock settings to new location");
287 // These Settings changed after multi-user was enabled, hence need to be moved per user.
288 if (getString("migrated_user_specific", null, 0) == null) {
289 final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
290 final ContentResolver cr = mContext.getContentResolver();
291 List<UserInfo> users = um.getUsers();
292 for (int user = 0; user < users.size(); user++) {
293 // Migrate owner info
294 final int userId = users.get(user).id;
295 final String OWNER_INFO = Secure.LOCK_SCREEN_OWNER_INFO;
296 String ownerInfo = Settings.Secure.getStringForUser(cr, OWNER_INFO, userId);
297 if (ownerInfo != null) {
298 setString(OWNER_INFO, ownerInfo, userId);
299 Settings.Secure.putStringForUser(cr, ownerInfo, "", userId);
302 // Migrate owner info enabled. Note there was a bug where older platforms only
303 // stored this value if the checkbox was toggled at least once. The code detects
304 // this case by handling the exception.
305 final String OWNER_INFO_ENABLED = Secure.LOCK_SCREEN_OWNER_INFO_ENABLED;
308 int ivalue = Settings.Secure.getIntForUser(cr, OWNER_INFO_ENABLED, userId);
309 enabled = ivalue != 0;
310 setLong(OWNER_INFO_ENABLED, enabled ? 1 : 0, userId);
311 } catch (SettingNotFoundException e) {
312 // Setting was never stored. Store it if the string is not empty.
313 if (!TextUtils.isEmpty(ownerInfo)) {
314 setLong(OWNER_INFO_ENABLED, 1, userId);
317 Settings.Secure.putIntForUser(cr, OWNER_INFO_ENABLED, 0, userId);
319 // No need to move the password / pattern files. They're already in the right place.
320 setString("migrated_user_specific", "true", 0);
321 Slog.i(TAG, "Migrated per-user lock settings to new location");
324 // Migrates biometric weak such that the fallback mechanism becomes the primary.
325 if (getString("migrated_biometric_weak", null, 0) == null) {
326 final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
327 List<UserInfo> users = um.getUsers();
328 for (int i = 0; i < users.size(); i++) {
329 int userId = users.get(i).id;
330 long type = getLong(LockPatternUtils.PASSWORD_TYPE_KEY,
331 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
333 long alternateType = getLong(LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY,
334 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
336 if (type == DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK) {
337 setLong(LockPatternUtils.PASSWORD_TYPE_KEY,
341 setLong(LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY,
342 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
345 setString("migrated_biometric_weak", "true", 0);
346 Slog.i(TAG, "Migrated biometric weak to use the fallback instead");
349 // Migrates lockscreen.disabled. Prior to M, the flag was ignored when more than one
350 // user was present on the system, so if we're upgrading to M and there is more than one
351 // user we disable the flag to remain consistent.
352 if (getString("migrated_lockscreen_disabled", null, 0) == null) {
353 final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
355 final List<UserInfo> users = um.getUsers();
356 final int userCount = users.size();
357 int switchableUsers = 0;
358 for (int i = 0; i < userCount; i++) {
359 if (users.get(i).supportsSwitchTo()) {
364 if (switchableUsers > 1) {
365 for (int i = 0; i < userCount; i++) {
366 int id = users.get(i).id;
368 if (getBoolean(LockPatternUtils.DISABLE_LOCKSCREEN_KEY, false, id)) {
369 setBoolean(LockPatternUtils.DISABLE_LOCKSCREEN_KEY, false, id);
374 setString("migrated_lockscreen_disabled", "true", 0);
375 Slog.i(TAG, "Migrated lockscreen disabled flag");
377 } catch (RemoteException re) {
378 Slog.e(TAG, "Unable to migrate old data", re);
382 private final void checkWritePermission(int userId) {
383 mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsWrite");
386 private final void checkPasswordReadPermission(int userId) {
387 mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsRead");
390 private final void checkReadPermission(String requestedKey, int userId) {
391 final int callingUid = Binder.getCallingUid();
393 for (int i = 0; i < READ_CONTACTS_PROTECTED_SETTINGS.length; i++) {
394 String key = READ_CONTACTS_PROTECTED_SETTINGS[i];
395 if (key.equals(requestedKey) && mContext.checkCallingOrSelfPermission(READ_CONTACTS)
396 != PackageManager.PERMISSION_GRANTED) {
397 throw new SecurityException("uid=" + callingUid
398 + " needs permission " + READ_CONTACTS + " to read "
399 + requestedKey + " for user " + userId);
403 for (int i = 0; i < READ_PASSWORD_PROTECTED_SETTINGS.length; i++) {
404 String key = READ_PASSWORD_PROTECTED_SETTINGS[i];
405 if (key.equals(requestedKey) && mContext.checkCallingOrSelfPermission(PERMISSION)
406 != PackageManager.PERMISSION_GRANTED) {
407 throw new SecurityException("uid=" + callingUid
408 + " needs permission " + PERMISSION + " to read "
409 + requestedKey + " for user " + userId);
415 public void setBoolean(String key, boolean value, int userId) throws RemoteException {
416 checkWritePermission(userId);
417 setStringUnchecked(key, userId, value ? "1" : "0");
421 public void setLong(String key, long value, int userId) throws RemoteException {
422 checkWritePermission(userId);
423 setStringUnchecked(key, userId, Long.toString(value));
427 public void setString(String key, String value, int userId) throws RemoteException {
428 checkWritePermission(userId);
429 setStringUnchecked(key, userId, value);
432 private void setStringUnchecked(String key, int userId, String value) {
433 mStorage.writeKeyValue(key, value, userId);
434 if (ArrayUtils.contains(SETTINGS_TO_BACKUP, key)) {
435 BackupManager.dataChanged("com.android.providers.settings");
440 public boolean getBoolean(String key, boolean defaultValue, int userId) throws RemoteException {
441 checkReadPermission(key, userId);
442 String value = getStringUnchecked(key, null, userId);
443 return TextUtils.isEmpty(value) ?
444 defaultValue : (value.equals("1") || value.equals("true"));
448 public long getLong(String key, long defaultValue, int userId) throws RemoteException {
449 checkReadPermission(key, userId);
451 String value = getStringUnchecked(key, null, userId);
452 return TextUtils.isEmpty(value) ? defaultValue : Long.parseLong(value);
456 public String getString(String key, String defaultValue, int userId) throws RemoteException {
457 checkReadPermission(key, userId);
459 return getStringUnchecked(key, defaultValue, userId);
462 public String getStringUnchecked(String key, String defaultValue, int userId) {
463 if (Settings.Secure.LOCK_PATTERN_ENABLED.equals(key)) {
464 long ident = Binder.clearCallingIdentity();
466 return mLockPatternUtils.isLockPatternEnabled(userId) ? "1" : "0";
468 Binder.restoreCallingIdentity(ident);
472 if (LockPatternUtils.LEGACY_LOCK_PATTERN_ENABLED.equals(key)) {
473 key = Settings.Secure.LOCK_PATTERN_ENABLED;
476 return mStorage.readKeyValue(key, defaultValue, userId);
480 public boolean havePassword(int userId) throws RemoteException {
481 // Do we need a permissions check here?
483 return mStorage.hasPassword(userId);
487 public boolean havePattern(int userId) throws RemoteException {
488 // Do we need a permissions check here?
490 return mStorage.hasPattern(userId);
493 private void setKeystorePassword(String password, int userHandle) {
494 final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
495 final KeyStore ks = KeyStore.getInstance();
497 final List<UserInfo> profiles = um.getProfiles(userHandle);
498 for (UserInfo pi : profiles) {
499 ks.onUserPasswordChanged(pi.id, password);
503 private void unlockKeystore(String password, int userHandle) {
504 final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
505 final KeyStore ks = KeyStore.getInstance();
507 final List<UserInfo> profiles = um.getProfiles(userHandle);
508 for (UserInfo pi : profiles) {
509 ks.unlock(pi.id, password);
513 private void unlockUser(int userId, byte[] token) {
515 ActivityManagerNative.getDefault().unlockUser(userId, token);
516 } catch (RemoteException e) {
517 throw e.rethrowAsRuntimeException();
521 private byte[] getCurrentHandle(int userId) {
522 CredentialHash credential;
523 byte[] currentHandle;
525 int currentHandleType = mStorage.getStoredCredentialType(userId);
526 switch (currentHandleType) {
527 case CredentialHash.TYPE_PATTERN:
528 credential = mStorage.readPatternHash(userId);
529 currentHandle = credential != null
533 case CredentialHash.TYPE_PASSWORD:
534 credential = mStorage.readPasswordHash(userId);
535 currentHandle = credential != null
539 case CredentialHash.TYPE_NONE:
541 currentHandle = null;
546 if (currentHandleType != CredentialHash.TYPE_NONE && currentHandle == null) {
547 Slog.e(TAG, "Stored handle type [" + currentHandleType + "] but no handle available");
550 return currentHandle;
555 public void setLockPattern(String pattern, String savedCredential, int userId)
556 throws RemoteException {
557 byte[] currentHandle = getCurrentHandle(userId);
559 if (pattern == null) {
560 getGateKeeperService().clearSecureUserId(userId);
561 mStorage.writePatternHash(null, userId);
562 setKeystorePassword(null, userId);
566 if (currentHandle == null) {
567 if (savedCredential != null) {
568 Slog.w(TAG, "Saved credential provided, but none stored");
570 savedCredential = null;
573 byte[] enrolledHandle = enrollCredential(currentHandle, savedCredential, pattern, userId);
574 if (enrolledHandle != null) {
575 mStorage.writePatternHash(enrolledHandle, userId);
577 throw new RemoteException("Failed to enroll pattern");
583 public void setLockPassword(String password, String savedCredential, int userId)
584 throws RemoteException {
585 byte[] currentHandle = getCurrentHandle(userId);
587 if (password == null) {
588 getGateKeeperService().clearSecureUserId(userId);
589 mStorage.writePasswordHash(null, userId);
590 setKeystorePassword(null, userId);
594 if (currentHandle == null) {
595 if (savedCredential != null) {
596 Slog.w(TAG, "Saved credential provided, but none stored");
598 savedCredential = null;
601 byte[] enrolledHandle = enrollCredential(currentHandle, savedCredential, password, userId);
602 if (enrolledHandle != null) {
603 mStorage.writePasswordHash(enrolledHandle, userId);
605 throw new RemoteException("Failed to enroll password");
609 private byte[] enrollCredential(byte[] enrolledHandle,
610 String enrolledCredential, String toEnroll, int userId)
611 throws RemoteException {
612 checkWritePermission(userId);
613 byte[] enrolledCredentialBytes = enrolledCredential == null
615 : enrolledCredential.getBytes();
616 byte[] toEnrollBytes = toEnroll == null
618 : toEnroll.getBytes();
619 GateKeeperResponse response = getGateKeeperService().enroll(userId, enrolledHandle,
620 enrolledCredentialBytes, toEnrollBytes);
622 if (response == null) {
626 byte[] hash = response.getPayload();
628 setKeystorePassword(toEnroll, userId);
631 Slog.e(TAG, "Throttled while enrolling a password");
637 public VerifyCredentialResponse checkPattern(String pattern, int userId) throws RemoteException {
638 return doVerifyPattern(pattern, false, 0, userId);
642 public VerifyCredentialResponse verifyPattern(String pattern, long challenge, int userId)
643 throws RemoteException {
644 return doVerifyPattern(pattern, true, challenge, userId);
647 private VerifyCredentialResponse doVerifyPattern(String pattern, boolean hasChallenge,
648 long challenge, int userId) throws RemoteException {
649 checkPasswordReadPermission(userId);
650 CredentialHash storedHash = mStorage.readPatternHash(userId);
651 boolean shouldReEnrollBaseZero = storedHash != null && storedHash.isBaseZeroPattern;
653 String patternToVerify;
654 if (shouldReEnrollBaseZero) {
655 patternToVerify = LockPatternUtils.patternStringToBaseZero(pattern);
657 patternToVerify = pattern;
660 VerifyCredentialResponse response = verifyCredential(userId, storedHash, patternToVerify,
661 hasChallenge, challenge,
662 new CredentialUtil() {
664 public void setCredential(String pattern, String oldPattern, int userId)
665 throws RemoteException {
666 setLockPattern(pattern, oldPattern, userId);
670 public byte[] toHash(String pattern, int userId) {
671 return LockPatternUtils.patternToHash(
672 LockPatternUtils.stringToPattern(pattern));
676 public String adjustForKeystore(String pattern) {
677 return LockPatternUtils.patternStringToBaseZero(pattern);
682 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK
683 && shouldReEnrollBaseZero) {
684 setLockPattern(pattern, patternToVerify, userId);
692 public VerifyCredentialResponse checkPassword(String password, int userId)
693 throws RemoteException {
694 return doVerifyPassword(password, false, 0, userId);
698 public VerifyCredentialResponse verifyPassword(String password, long challenge, int userId)
699 throws RemoteException {
700 return doVerifyPassword(password, true, challenge, userId);
703 private VerifyCredentialResponse doVerifyPassword(String password, boolean hasChallenge,
704 long challenge, int userId) throws RemoteException {
705 checkPasswordReadPermission(userId);
706 CredentialHash storedHash = mStorage.readPasswordHash(userId);
707 return verifyCredential(userId, storedHash, password, hasChallenge, challenge,
708 new CredentialUtil() {
710 public void setCredential(String password, String oldPassword, int userId)
711 throws RemoteException {
712 setLockPassword(password, oldPassword, userId);
716 public byte[] toHash(String password, int userId) {
717 return mLockPatternUtils.passwordToHash(password, userId);
721 public String adjustForKeystore(String password) {
728 private VerifyCredentialResponse verifyCredential(int userId, CredentialHash storedHash,
729 String credential, boolean hasChallenge, long challenge, CredentialUtil credentialUtil)
730 throws RemoteException {
731 if ((storedHash == null || storedHash.hash.length == 0) && TextUtils.isEmpty(credential)) {
732 // don't need to pass empty credentials to GateKeeper
733 return VerifyCredentialResponse.OK;
736 if (TextUtils.isEmpty(credential)) {
737 return VerifyCredentialResponse.ERROR;
740 if (storedHash.version == CredentialHash.VERSION_LEGACY) {
741 byte[] hash = credentialUtil.toHash(credential, userId);
742 if (Arrays.equals(hash, storedHash.hash)) {
743 unlockKeystore(credentialUtil.adjustForKeystore(credential), userId);
745 // TODO: pass through a meaningful token from gatekeeper to
746 // unlock credential keys; for now pass through a stub value to
747 // indicate that we came from a user challenge.
748 final byte[] token = String.valueOf(userId).getBytes();
749 unlockUser(userId, token);
751 // migrate credential to GateKeeper
752 credentialUtil.setCredential(credential, null, userId);
754 return VerifyCredentialResponse.OK;
756 // Fall through to get the auth token. Technically this should never happen,
757 // as a user that had a legacy credential would have to unlock their device
758 // before getting to a flow with a challenge, but supporting for consistency.
760 return VerifyCredentialResponse.ERROR;
764 VerifyCredentialResponse response;
765 boolean shouldReEnroll = false;;
768 GateKeeperResponse gateKeeperResponse = getGateKeeperService()
769 .verifyChallenge(userId, challenge, storedHash.hash, credential.getBytes());
770 int responseCode = gateKeeperResponse.getResponseCode();
771 if (responseCode == GateKeeperResponse.RESPONSE_RETRY) {
772 response = new VerifyCredentialResponse(gateKeeperResponse.getTimeout());
773 } else if (responseCode == GateKeeperResponse.RESPONSE_OK) {
774 token = gateKeeperResponse.getPayload();
776 // something's wrong if there's no payload with a challenge
777 Slog.e(TAG, "verifyChallenge response had no associated payload");
778 response = VerifyCredentialResponse.ERROR;
780 shouldReEnroll = gateKeeperResponse.getShouldReEnroll();
781 response = new VerifyCredentialResponse(token);
784 response = VerifyCredentialResponse.ERROR;
787 GateKeeperResponse gateKeeperResponse = getGateKeeperService().verify(
788 userId, storedHash.hash, credential.getBytes());
789 int responseCode = gateKeeperResponse.getResponseCode();
790 if (responseCode == GateKeeperResponse.RESPONSE_RETRY) {
791 response = new VerifyCredentialResponse(gateKeeperResponse.getTimeout());
792 } else if (responseCode == GateKeeperResponse.RESPONSE_OK) {
793 shouldReEnroll = gateKeeperResponse.getShouldReEnroll();
794 response = VerifyCredentialResponse.OK;
796 response = VerifyCredentialResponse.ERROR;
800 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
801 // credential has matched
802 unlockKeystore(credential, userId);
804 // TODO: pass through a meaningful token from gatekeeper to
805 // unlock credential keys; for now pass through a stub value to
806 // indicate that we came from a user challenge.
807 final byte[] token = String.valueOf(userId).getBytes();
808 unlockUser(userId, token);
810 UserInfo info = UserManager.get(mContext).getUserInfo(userId);
811 if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)) {
812 TrustManager trustManager =
813 (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
814 trustManager.setDeviceLockedForUser(userId, false);
816 if (shouldReEnroll) {
817 credentialUtil.setCredential(credential, credential, userId);
819 } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
820 if (response.getTimeout() > 0) {
821 requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_LOCKOUT, userId);
829 public boolean checkVoldPassword(int userId) throws RemoteException {
830 if (!mFirstCallToVold) {
833 mFirstCallToVold = false;
835 checkPasswordReadPermission(userId);
837 // There's no guarantee that this will safely connect, but if it fails
838 // we will simply show the lock screen when we shouldn't, so relatively
839 // benign. There is an outside chance something nasty would happen if
840 // this service restarted before vold stales out the password in this
841 // case. The nastiness is limited to not showing the lock screen when
842 // we should, within the first minute of decrypting the phone if this
843 // service can't connect to vold, it restarts, and then the new instance
844 // does successfully connect.
845 final IMountService service = getMountService();
846 String password = service.getPassword();
847 service.clearPassword();
848 if (password == null) {
853 if (mLockPatternUtils.isLockPatternEnabled(userId)) {
854 if (checkPattern(password, userId).getResponseCode()
855 == GateKeeperResponse.RESPONSE_OK) {
859 } catch (Exception e) {
863 if (mLockPatternUtils.isLockPasswordEnabled(userId)) {
864 if (checkPassword(password, userId).getResponseCode()
865 == GateKeeperResponse.RESPONSE_OK) {
869 } catch (Exception e) {
875 private void removeUser(int userId) {
876 mStorage.removeUser(userId);
877 mStrongAuth.removeUser(userId);
879 final KeyStore ks = KeyStore.getInstance();
880 ks.onUserRemoved(userId);
883 final IGateKeeperService gk = getGateKeeperService();
885 gk.clearSecureUserId(userId);
887 } catch (RemoteException ex) {
888 Slog.w(TAG, "unable to clear GK secure user id");
893 public void registerStrongAuthTracker(IStrongAuthTracker tracker) {
894 checkPasswordReadPermission(UserHandle.USER_ALL);
895 mStrongAuth.registerStrongAuthTracker(tracker);
899 public void unregisterStrongAuthTracker(IStrongAuthTracker tracker) {
900 checkPasswordReadPermission(UserHandle.USER_ALL);
901 mStrongAuth.unregisterStrongAuthTracker(tracker);
905 public void requireStrongAuth(int strongAuthReason, int userId) {
906 checkWritePermission(userId);
907 mStrongAuth.requireStrongAuth(strongAuthReason, userId);
910 private static final String[] VALID_SETTINGS = new String[] {
911 LockPatternUtils.LOCKOUT_PERMANENT_KEY,
912 LockPatternUtils.LOCKOUT_ATTEMPT_DEADLINE,
913 LockPatternUtils.PATTERN_EVER_CHOSEN_KEY,
914 LockPatternUtils.PASSWORD_TYPE_KEY,
915 LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY,
916 LockPatternUtils.LOCK_PASSWORD_SALT_KEY,
917 LockPatternUtils.DISABLE_LOCKSCREEN_KEY,
918 LockPatternUtils.LOCKSCREEN_OPTIONS,
919 LockPatternUtils.LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK,
920 LockPatternUtils.BIOMETRIC_WEAK_EVER_CHOSEN_KEY,
921 LockPatternUtils.LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS,
922 LockPatternUtils.PASSWORD_HISTORY_KEY,
923 Secure.LOCK_PATTERN_ENABLED,
924 Secure.LOCK_BIOMETRIC_WEAK_FLAGS,
925 Secure.LOCK_PATTERN_VISIBLE,
926 Secure.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED
929 // Reading these settings needs the contacts permission
930 private static final String[] READ_CONTACTS_PROTECTED_SETTINGS = new String[] {
931 Secure.LOCK_SCREEN_OWNER_INFO_ENABLED,
932 Secure.LOCK_SCREEN_OWNER_INFO
935 // Reading these settings needs the same permission as checking the password
936 private static final String[] READ_PASSWORD_PROTECTED_SETTINGS = new String[] {
937 LockPatternUtils.LOCK_PASSWORD_SALT_KEY,
938 LockPatternUtils.PASSWORD_HISTORY_KEY,
939 LockPatternUtils.PASSWORD_TYPE_KEY,
942 private static final String[] SETTINGS_TO_BACKUP = new String[] {
943 Secure.LOCK_SCREEN_OWNER_INFO_ENABLED,
944 Secure.LOCK_SCREEN_OWNER_INFO
947 private IMountService getMountService() {
948 final IBinder service = ServiceManager.getService("mount");
949 if (service != null) {
950 return IMountService.Stub.asInterface(service);
955 private class GateKeeperDiedRecipient implements IBinder.DeathRecipient {
957 public void binderDied() {
958 mGateKeeperService.asBinder().unlinkToDeath(this, 0);
959 mGateKeeperService = null;
963 private synchronized IGateKeeperService getGateKeeperService()
964 throws RemoteException {
965 if (mGateKeeperService != null) {
966 return mGateKeeperService;
969 final IBinder service =
970 ServiceManager.getService("android.service.gatekeeper.IGateKeeperService");
971 if (service != null) {
972 service.linkToDeath(new GateKeeperDiedRecipient(), 0);
973 mGateKeeperService = IGateKeeperService.Stub.asInterface(service);
974 return mGateKeeperService;
977 Slog.e(TAG, "Unable to acquire GateKeeperService");