OSDN Git Service

Merge "Attempt to fix bug where OwnerInfo gets lost." into nyc-dev
[android-x86/frameworks-base.git] / services / core / java / com / android / server / LockSettingsService.java
1 /*
2  * Copyright (C) 2012 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package com.android.server;
18
19 import android.app.ActivityManagerNative;
20 import android.app.KeyguardManager;
21 import android.app.Notification;
22 import android.app.NotificationManager;
23 import android.app.PendingIntent;
24 import android.app.admin.DevicePolicyManager;
25 import android.app.backup.BackupManager;
26 import android.app.trust.IStrongAuthTracker;
27 import android.app.trust.TrustManager;
28 import android.content.BroadcastReceiver;
29 import android.content.ContentResolver;
30 import android.content.Context;
31 import android.content.Intent;
32 import android.content.IntentFilter;
33 import android.content.pm.PackageManager;
34 import android.content.pm.UserInfo;
35 import android.content.res.Resources;
36
37 import static android.Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE;
38 import static android.content.Context.KEYGUARD_SERVICE;
39 import static android.content.Context.USER_SERVICE;
40 import static android.Manifest.permission.READ_CONTACTS;
41 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
42
43 import android.database.sqlite.SQLiteDatabase;
44 import android.os.Binder;
45 import android.os.IBinder;
46 import android.os.RemoteException;
47 import android.os.storage.IMountService;
48 import android.os.ServiceManager;
49 import android.os.SystemProperties;
50 import android.os.UserHandle;
51 import android.os.UserManager;
52 import android.provider.Settings;
53 import android.provider.Settings.Secure;
54 import android.provider.Settings.SettingNotFoundException;
55 import android.security.KeyStore;
56 import android.service.gatekeeper.GateKeeperResponse;
57 import android.service.gatekeeper.IGateKeeperService;
58 import android.text.TextUtils;
59 import android.util.Slog;
60
61 import com.android.internal.util.ArrayUtils;
62 import com.android.internal.widget.ILockSettings;
63 import com.android.internal.widget.LockPatternUtils;
64 import com.android.internal.widget.VerifyCredentialResponse;
65 import com.android.server.LockSettingsStorage.CredentialHash;
66
67 import java.nio.charset.StandardCharsets;
68 import java.security.MessageDigest;
69 import java.security.NoSuchAlgorithmException;
70
71 import java.util.Arrays;
72 import java.util.List;
73
74 /**
75  * Keeps the lock pattern/password data and related settings for each user.
76  * Used by LockPatternUtils. Needs to be a service because Settings app also needs
77  * to be able to save lockscreen information for secondary users.
78  * @hide
79  */
80 public class LockSettingsService extends ILockSettings.Stub {
81     private static final String TAG = "LockSettingsService";
82     private static final String PERMISSION = ACCESS_KEYGUARD_SECURE_STORAGE;
83     private static final Intent ACTION_NULL; // hack to ensure notification shows the bouncer
84     private static final int FBE_ENCRYPTED_NOTIFICATION = 0;
85     private static final boolean DEBUG = false;
86
87     private final Context mContext;
88     private final LockSettingsStorage mStorage;
89     private final LockSettingsStrongAuth mStrongAuth;
90
91     private LockPatternUtils mLockPatternUtils;
92     private boolean mFirstCallToVold;
93     private IGateKeeperService mGateKeeperService;
94     private NotificationManager mNotificationManager;
95     private UserManager mUserManager;
96
97     static {
98         // Just launch the home screen, which happens anyway
99         ACTION_NULL = new Intent(Intent.ACTION_MAIN);
100         ACTION_NULL.addCategory(Intent.CATEGORY_HOME);
101     }
102
103     private interface CredentialUtil {
104         void setCredential(String credential, String savedCredential, int userId)
105                 throws RemoteException;
106         byte[] toHash(String credential, int userId);
107         String adjustForKeystore(String credential);
108     }
109
110     // This class manages life cycle events for encrypted users on File Based Encryption (FBE)
111     // devices. The most basic of these is to show/hide notifications about missing features until
112     // the user unlocks the account and credential-encrypted storage is available.
113     public static final class Lifecycle extends SystemService {
114         private LockSettingsService mLockSettingsService;
115
116         public Lifecycle(Context context) {
117             super(context);
118         }
119
120         @Override
121         public void onStart() {
122             mLockSettingsService = new LockSettingsService(getContext());
123             publishBinderService("lock_settings", mLockSettingsService);
124         }
125
126         @Override
127         public void onBootPhase(int phase) {
128             if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
129                 mLockSettingsService.maybeShowEncryptionNotifications();
130             } else if (phase == SystemService.PHASE_BOOT_COMPLETED) {
131                 // TODO
132             }
133         }
134
135         @Override
136         public void onUnlockUser(int userHandle) {
137             mLockSettingsService.onUnlockUser(userHandle);
138         }
139
140         @Override
141         public void onCleanupUser(int userHandle) {
142             mLockSettingsService.onCleanupUser(userHandle);
143         }
144     }
145
146     public LockSettingsService(Context context) {
147         mContext = context;
148         mStrongAuth = new LockSettingsStrongAuth(context);
149         // Open the database
150
151         mLockPatternUtils = new LockPatternUtils(context);
152         mFirstCallToVold = true;
153
154         IntentFilter filter = new IntentFilter();
155         filter.addAction(Intent.ACTION_USER_ADDED);
156         filter.addAction(Intent.ACTION_USER_STARTING);
157         filter.addAction(Intent.ACTION_USER_REMOVED);
158         filter.addAction(Intent.ACTION_USER_PRESENT);
159         mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
160
161         mStorage = new LockSettingsStorage(context, new LockSettingsStorage.Callback() {
162             @Override
163             public void initialize(SQLiteDatabase db) {
164                 // Get the lockscreen default from a system property, if available
165                 boolean lockScreenDisable = SystemProperties.getBoolean(
166                         "ro.lockscreen.disable.default", false);
167                 if (lockScreenDisable) {
168                     mStorage.writeKeyValue(db, LockPatternUtils.DISABLE_LOCKSCREEN_KEY, "1", 0);
169                 }
170             }
171         });
172         mNotificationManager = (NotificationManager)
173                 mContext.getSystemService(Context.NOTIFICATION_SERVICE);
174         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
175     }
176
177     /**
178      * If the account is credential-encrypted, show notification requesting the user to unlock
179      * the device.
180      */
181     private void maybeShowEncryptionNotifications() {
182         final List<UserInfo> users = mUserManager.getUsers();
183         for (int i = 0; i < users.size(); i++) {
184             UserInfo user = users.get(i);
185             UserHandle userHandle = user.getUserHandle();
186             if (!mUserManager.isUserUnlocked(userHandle)) {
187                 if (!user.isManagedProfile()) {
188                     showEncryptionNotification(userHandle);
189                 } else {
190                     UserInfo parent = mUserManager.getProfileParent(user.id);
191                     if (parent != null && mUserManager.isUserUnlocked(parent.getUserHandle())) {
192                         // Only show notifications for managed profiles once their parent
193                         // user is unlocked.
194                         showEncryptionNotificationForProfile(userHandle);
195                     }
196                 }
197             }
198         }
199     }
200
201     private void showEncryptionNotificationForProfile(UserHandle user) {
202         Resources r = mContext.getResources();
203         CharSequence title = r.getText(
204                 com.android.internal.R.string.user_encrypted_title);
205         CharSequence message = r.getText(
206                 com.android.internal.R.string.profile_encrypted_message);
207         CharSequence detail = r.getText(
208                 com.android.internal.R.string.profile_encrypted_detail);
209
210         final KeyguardManager km = (KeyguardManager) mContext.getSystemService(KEYGUARD_SERVICE);
211         final Intent unlockIntent = km.createConfirmDeviceCredentialIntent(null, null, user.getIdentifier());
212         if (unlockIntent == null) {
213             return;
214         }
215         unlockIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
216         PendingIntent intent = PendingIntent.getActivity(mContext, 0, unlockIntent,
217                 PendingIntent.FLAG_UPDATE_CURRENT);
218
219         showEncryptionNotification(user, title, message, detail, intent);
220     }
221
222     private void showEncryptionNotification(UserHandle user) {
223         Resources r = mContext.getResources();
224         CharSequence title = r.getText(
225                 com.android.internal.R.string.user_encrypted_title);
226         CharSequence message = r.getText(
227                 com.android.internal.R.string.user_encrypted_message);
228         CharSequence detail = r.getText(
229                 com.android.internal.R.string.user_encrypted_detail);
230
231         PendingIntent intent = PendingIntent.getBroadcast(mContext, 0, ACTION_NULL,
232                 PendingIntent.FLAG_UPDATE_CURRENT);
233
234         showEncryptionNotification(user, title, message, detail, intent);
235     }
236
237     private void showEncryptionNotification(UserHandle user, CharSequence title, CharSequence message,
238             CharSequence detail, PendingIntent intent) {
239         if (DEBUG) Slog.v(TAG, "showing encryption notification, user: " + user.getIdentifier());
240         Notification notification = new Notification.Builder(mContext)
241                 .setSmallIcon(com.android.internal.R.drawable.ic_user_secure)
242                 .setWhen(0)
243                 .setOngoing(true)
244                 .setTicker(title)
245                 .setDefaults(0)  // please be quiet
246                 .setPriority(Notification.PRIORITY_MAX)
247                 .setColor(mContext.getColor(
248                         com.android.internal.R.color.system_notification_accent_color))
249                 .setContentTitle(title)
250                 .setContentText(message)
251                 .setContentInfo(detail)
252                 .setVisibility(Notification.VISIBILITY_PUBLIC)
253                 .setContentIntent(intent)
254                 .build();
255         mNotificationManager.notifyAsUser(null, FBE_ENCRYPTED_NOTIFICATION, notification, user);
256     }
257
258     public void hideEncryptionNotification(UserHandle userHandle) {
259         if (DEBUG) Slog.v(TAG, "hide encryption notification, user: "+ userHandle.getIdentifier());
260         mNotificationManager.cancelAsUser(null, FBE_ENCRYPTED_NOTIFICATION, userHandle);
261     }
262
263     public void onCleanupUser(int userId) {
264         hideEncryptionNotification(new UserHandle(userId));
265     }
266
267     public void onUnlockUser(int userId) {
268         hideEncryptionNotification(new UserHandle(userId));
269
270         // Now we have unlocked the parent user we should show notifications
271         // about any profiles that exist.
272         List<UserInfo> profiles = mUserManager.getProfiles(userId);
273         for (int i = 0; i < profiles.size(); i++) {
274             UserInfo profile = profiles.get(i);
275             if (profile.isManagedProfile()) {
276                 UserHandle userHandle = profile.getUserHandle();
277                 if (!mUserManager.isUserUnlocked(userHandle)) {
278                     showEncryptionNotificationForProfile(userHandle);
279                 }
280             }
281         }
282     }
283
284     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
285         @Override
286         public void onReceive(Context context, Intent intent) {
287             if (Intent.ACTION_USER_ADDED.equals(intent.getAction())) {
288                 // Notify keystore that a new user was added.
289                 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
290                 final KeyStore ks = KeyStore.getInstance();
291                 final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
292                 final UserInfo parentInfo = um.getProfileParent(userHandle);
293                 final int parentHandle = parentInfo != null ? parentInfo.id : -1;
294                 ks.onUserAdded(userHandle, parentHandle);
295             } else if (Intent.ACTION_USER_STARTING.equals(intent.getAction())) {
296                 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
297                 mStorage.prefetchUser(userHandle);
298             } else if (Intent.ACTION_USER_PRESENT.equals(intent.getAction())) {
299                 mStrongAuth.reportUnlock(getSendingUserId());
300             } else if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
301                 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
302                 if (userHandle > 0) {
303                     removeUser(userHandle);
304                 }
305             }
306         }
307     };
308
309     @Override // binder interface
310     public void systemReady() {
311         migrateOldData();
312         try {
313             getGateKeeperService();
314         } catch (RemoteException e) {
315             Slog.e(TAG, "Failure retrieving IGateKeeperService", e);
316         }
317         // TODO: maybe skip this for split system user mode.
318         mStorage.prefetchUser(UserHandle.USER_SYSTEM);
319     }
320
321     private void migrateOldData() {
322         try {
323             // These Settings moved before multi-user was enabled, so we only have to do it for the
324             // root user.
325             if (getString("migrated", null, 0) == null) {
326                 final ContentResolver cr = mContext.getContentResolver();
327                 for (String validSetting : VALID_SETTINGS) {
328                     String value = Settings.Secure.getString(cr, validSetting);
329                     if (value != null) {
330                         setString(validSetting, value, 0);
331                     }
332                 }
333                 // No need to move the password / pattern files. They're already in the right place.
334                 setString("migrated", "true", 0);
335                 Slog.i(TAG, "Migrated lock settings to new location");
336             }
337
338             // These Settings changed after multi-user was enabled, hence need to be moved per user.
339             if (getString("migrated_user_specific", null, 0) == null) {
340                 final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
341                 final ContentResolver cr = mContext.getContentResolver();
342                 List<UserInfo> users = um.getUsers();
343                 for (int user = 0; user < users.size(); user++) {
344                     // Migrate owner info
345                     final int userId = users.get(user).id;
346                     final String OWNER_INFO = Secure.LOCK_SCREEN_OWNER_INFO;
347                     String ownerInfo = Settings.Secure.getStringForUser(cr, OWNER_INFO, userId);
348                     if (!TextUtils.isEmpty(ownerInfo)) {
349                         setString(OWNER_INFO, ownerInfo, userId);
350                         Settings.Secure.putStringForUser(cr, OWNER_INFO, "", userId);
351                     }
352
353                     // Migrate owner info enabled.  Note there was a bug where older platforms only
354                     // stored this value if the checkbox was toggled at least once. The code detects
355                     // this case by handling the exception.
356                     final String OWNER_INFO_ENABLED = Secure.LOCK_SCREEN_OWNER_INFO_ENABLED;
357                     boolean enabled;
358                     try {
359                         int ivalue = Settings.Secure.getIntForUser(cr, OWNER_INFO_ENABLED, userId);
360                         enabled = ivalue != 0;
361                         setLong(OWNER_INFO_ENABLED, enabled ? 1 : 0, userId);
362                     } catch (SettingNotFoundException e) {
363                         // Setting was never stored. Store it if the string is not empty.
364                         if (!TextUtils.isEmpty(ownerInfo)) {
365                             setLong(OWNER_INFO_ENABLED, 1, userId);
366                         }
367                     }
368                     Settings.Secure.putIntForUser(cr, OWNER_INFO_ENABLED, 0, userId);
369                 }
370                 // No need to move the password / pattern files. They're already in the right place.
371                 setString("migrated_user_specific", "true", 0);
372                 Slog.i(TAG, "Migrated per-user lock settings to new location");
373             }
374
375             // Migrates biometric weak such that the fallback mechanism becomes the primary.
376             if (getString("migrated_biometric_weak", null, 0) == null) {
377                 final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
378                 List<UserInfo> users = um.getUsers();
379                 for (int i = 0; i < users.size(); i++) {
380                     int userId = users.get(i).id;
381                     long type = getLong(LockPatternUtils.PASSWORD_TYPE_KEY,
382                             DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
383                             userId);
384                     long alternateType = getLong(LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY,
385                             DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
386                             userId);
387                     if (type == DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK) {
388                         setLong(LockPatternUtils.PASSWORD_TYPE_KEY,
389                                 alternateType,
390                                 userId);
391                     }
392                     setLong(LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY,
393                             DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
394                             userId);
395                 }
396                 setString("migrated_biometric_weak", "true", 0);
397                 Slog.i(TAG, "Migrated biometric weak to use the fallback instead");
398             }
399
400             // Migrates lockscreen.disabled. Prior to M, the flag was ignored when more than one
401             // user was present on the system, so if we're upgrading to M and there is more than one
402             // user we disable the flag to remain consistent.
403             if (getString("migrated_lockscreen_disabled", null, 0) == null) {
404                 final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
405
406                 final List<UserInfo> users = um.getUsers();
407                 final int userCount = users.size();
408                 int switchableUsers = 0;
409                 for (int i = 0; i < userCount; i++) {
410                     if (users.get(i).supportsSwitchTo()) {
411                         switchableUsers++;
412                     }
413                 }
414
415                 if (switchableUsers > 1) {
416                     for (int i = 0; i < userCount; i++) {
417                         int id = users.get(i).id;
418
419                         if (getBoolean(LockPatternUtils.DISABLE_LOCKSCREEN_KEY, false, id)) {
420                             setBoolean(LockPatternUtils.DISABLE_LOCKSCREEN_KEY, false, id);
421                         }
422                     }
423                 }
424
425                 setString("migrated_lockscreen_disabled", "true", 0);
426                 Slog.i(TAG, "Migrated lockscreen disabled flag");
427             }
428         } catch (RemoteException re) {
429             Slog.e(TAG, "Unable to migrate old data", re);
430         }
431     }
432
433     private final void checkWritePermission(int userId) {
434         mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsWrite");
435     }
436
437     private final void checkPasswordReadPermission(int userId) {
438         mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsRead");
439     }
440
441     private final void checkReadPermission(String requestedKey, int userId) {
442         final int callingUid = Binder.getCallingUid();
443
444         for (int i = 0; i < READ_CONTACTS_PROTECTED_SETTINGS.length; i++) {
445             String key = READ_CONTACTS_PROTECTED_SETTINGS[i];
446             if (key.equals(requestedKey) && mContext.checkCallingOrSelfPermission(READ_CONTACTS)
447                     != PackageManager.PERMISSION_GRANTED) {
448                 throw new SecurityException("uid=" + callingUid
449                         + " needs permission " + READ_CONTACTS + " to read "
450                         + requestedKey + " for user " + userId);
451             }
452         }
453
454         for (int i = 0; i < READ_PASSWORD_PROTECTED_SETTINGS.length; i++) {
455             String key = READ_PASSWORD_PROTECTED_SETTINGS[i];
456             if (key.equals(requestedKey) && mContext.checkCallingOrSelfPermission(PERMISSION)
457                     != PackageManager.PERMISSION_GRANTED) {
458                 throw new SecurityException("uid=" + callingUid
459                         + " needs permission " + PERMISSION + " to read "
460                         + requestedKey + " for user " + userId);
461             }
462         }
463     }
464
465     @Override
466     public void setBoolean(String key, boolean value, int userId) throws RemoteException {
467         checkWritePermission(userId);
468         setStringUnchecked(key, userId, value ? "1" : "0");
469     }
470
471     @Override
472     public void setLong(String key, long value, int userId) throws RemoteException {
473         checkWritePermission(userId);
474         setStringUnchecked(key, userId, Long.toString(value));
475     }
476
477     @Override
478     public void setString(String key, String value, int userId) throws RemoteException {
479         checkWritePermission(userId);
480         setStringUnchecked(key, userId, value);
481     }
482
483     private void setStringUnchecked(String key, int userId, String value) {
484         mStorage.writeKeyValue(key, value, userId);
485         if (ArrayUtils.contains(SETTINGS_TO_BACKUP, key)) {
486             BackupManager.dataChanged("com.android.providers.settings");
487         }
488     }
489
490     @Override
491     public boolean getBoolean(String key, boolean defaultValue, int userId) throws RemoteException {
492         checkReadPermission(key, userId);
493         String value = getStringUnchecked(key, null, userId);
494         return TextUtils.isEmpty(value) ?
495                 defaultValue : (value.equals("1") || value.equals("true"));
496     }
497
498     @Override
499     public long getLong(String key, long defaultValue, int userId) throws RemoteException {
500         checkReadPermission(key, userId);
501
502         String value = getStringUnchecked(key, null, userId);
503         return TextUtils.isEmpty(value) ? defaultValue : Long.parseLong(value);
504     }
505
506     @Override
507     public String getString(String key, String defaultValue, int userId) throws RemoteException {
508         checkReadPermission(key, userId);
509
510         return getStringUnchecked(key, defaultValue, userId);
511     }
512
513     public String getStringUnchecked(String key, String defaultValue, int userId) {
514         if (Settings.Secure.LOCK_PATTERN_ENABLED.equals(key)) {
515             long ident = Binder.clearCallingIdentity();
516             try {
517                 return mLockPatternUtils.isLockPatternEnabled(userId) ? "1" : "0";
518             } finally {
519                 Binder.restoreCallingIdentity(ident);
520             }
521         }
522
523         if (LockPatternUtils.LEGACY_LOCK_PATTERN_ENABLED.equals(key)) {
524             key = Settings.Secure.LOCK_PATTERN_ENABLED;
525         }
526
527         return mStorage.readKeyValue(key, defaultValue, userId);
528     }
529
530     @Override
531     public boolean havePassword(int userId) throws RemoteException {
532         // Do we need a permissions check here?
533
534         return mStorage.hasPassword(userId);
535     }
536
537     @Override
538     public boolean havePattern(int userId) throws RemoteException {
539         // Do we need a permissions check here?
540
541         return mStorage.hasPattern(userId);
542     }
543
544     private void setKeystorePassword(String password, int userHandle) {
545         final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
546         final KeyStore ks = KeyStore.getInstance();
547
548         if (um.getUserInfo(userHandle).isManagedProfile()) {
549             if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userHandle)) {
550                 ks.onUserPasswordChanged(userHandle, password);
551             } else {
552                 throw new RuntimeException("Can't set keystore password on a profile that "
553                         + "doesn't have a profile challenge.");
554             }
555         } else {
556             final List<UserInfo> profiles = um.getProfiles(userHandle);
557             for (UserInfo pi : profiles) {
558                 // Change password on the given user and all its profiles that don't have
559                 // their own profile challenge enabled.
560                 if (pi.id == userHandle || (pi.isManagedProfile()
561                         && !mLockPatternUtils.isSeparateProfileChallengeEnabled(pi.id))) {
562                     ks.onUserPasswordChanged(pi.id, password);
563                 }
564             }
565         }
566     }
567
568     private void unlockKeystore(String password, int userHandle) {
569         final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
570         final KeyStore ks = KeyStore.getInstance();
571
572         if (um.getUserInfo(userHandle).isManagedProfile()) {
573             if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userHandle)) {
574                 ks.unlock(userHandle, password);
575             } else {
576                 throw new RuntimeException("Can't unlock a profile explicitly if it "
577                         + "doesn't have a profile challenge.");
578             }
579         } else {
580             final List<UserInfo> profiles = um.getProfiles(userHandle);
581             for (UserInfo pi : profiles) {
582                 // Unlock the given user and all its profiles that don't have
583                 // their own profile challenge enabled.
584                 if (pi.id == userHandle || (pi.isManagedProfile()
585                         && !mLockPatternUtils.isSeparateProfileChallengeEnabled(pi.id))) {
586                     ks.unlock(pi.id, password);
587                 }
588             }
589         }
590     }
591
592     private void unlockUser(int userId, byte[] token, byte[] secret) {
593         try {
594             ActivityManagerNative.getDefault().unlockUser(userId, token, secret);
595         } catch (RemoteException e) {
596             throw e.rethrowAsRuntimeException();
597         }
598     }
599
600     private byte[] getCurrentHandle(int userId) {
601         CredentialHash credential;
602         byte[] currentHandle;
603
604         int currentHandleType = mStorage.getStoredCredentialType(userId);
605         switch (currentHandleType) {
606             case CredentialHash.TYPE_PATTERN:
607                 credential = mStorage.readPatternHash(userId);
608                 currentHandle = credential != null
609                         ? credential.hash
610                         : null;
611                 break;
612             case CredentialHash.TYPE_PASSWORD:
613                 credential = mStorage.readPasswordHash(userId);
614                 currentHandle = credential != null
615                         ? credential.hash
616                         : null;
617                 break;
618             case CredentialHash.TYPE_NONE:
619             default:
620                 currentHandle = null;
621                 break;
622         }
623
624         // sanity check
625         if (currentHandleType != CredentialHash.TYPE_NONE && currentHandle == null) {
626             Slog.e(TAG, "Stored handle type [" + currentHandleType + "] but no handle available");
627         }
628
629         return currentHandle;
630     }
631
632
633     @Override
634     public void setLockPattern(String pattern, String savedCredential, int userId)
635             throws RemoteException {
636         byte[] currentHandle = getCurrentHandle(userId);
637
638         if (pattern == null) {
639             getGateKeeperService().clearSecureUserId(userId);
640             mStorage.writePatternHash(null, userId);
641             setKeystorePassword(null, userId);
642             clearUserKeyProtection(userId);
643             return;
644         }
645
646         if (currentHandle == null) {
647             if (savedCredential != null) {
648                 Slog.w(TAG, "Saved credential provided, but none stored");
649             }
650             savedCredential = null;
651         }
652
653         byte[] enrolledHandle = enrollCredential(currentHandle, savedCredential, pattern, userId);
654         if (enrolledHandle != null) {
655             mStorage.writePatternHash(enrolledHandle, userId);
656             setUserKeyProtection(userId, pattern, verifyPattern(pattern, 0, userId));
657         } else {
658             throw new RemoteException("Failed to enroll pattern");
659         }
660     }
661
662
663     @Override
664     public void setLockPassword(String password, String savedCredential, int userId)
665             throws RemoteException {
666         byte[] currentHandle = getCurrentHandle(userId);
667
668         if (password == null) {
669             getGateKeeperService().clearSecureUserId(userId);
670             mStorage.writePasswordHash(null, userId);
671             setKeystorePassword(null, userId);
672             clearUserKeyProtection(userId);
673             return;
674         }
675
676         if (currentHandle == null) {
677             if (savedCredential != null) {
678                 Slog.w(TAG, "Saved credential provided, but none stored");
679             }
680             savedCredential = null;
681         }
682
683         byte[] enrolledHandle = enrollCredential(currentHandle, savedCredential, password, userId);
684         if (enrolledHandle != null) {
685             mStorage.writePasswordHash(enrolledHandle, userId);
686             setUserKeyProtection(userId, password, verifyPassword(password, 0, userId));
687         } else {
688             throw new RemoteException("Failed to enroll password");
689         }
690     }
691
692     private byte[] enrollCredential(byte[] enrolledHandle,
693             String enrolledCredential, String toEnroll, int userId)
694             throws RemoteException {
695         checkWritePermission(userId);
696         byte[] enrolledCredentialBytes = enrolledCredential == null
697                 ? null
698                 : enrolledCredential.getBytes();
699         byte[] toEnrollBytes = toEnroll == null
700                 ? null
701                 : toEnroll.getBytes();
702         GateKeeperResponse response = getGateKeeperService().enroll(userId, enrolledHandle,
703                 enrolledCredentialBytes, toEnrollBytes);
704
705         if (response == null) {
706             return null;
707         }
708
709         byte[] hash = response.getPayload();
710         if (hash != null) {
711             setKeystorePassword(toEnroll, userId);
712         } else {
713             // Should not happen
714             Slog.e(TAG, "Throttled while enrolling a password");
715         }
716         return hash;
717     }
718
719     private void setUserKeyProtection(int userId, String credential, VerifyCredentialResponse vcr)
720             throws RemoteException {
721         if (vcr == null) {
722             throw new RemoteException("Null response verifying a credential we just set");
723         }
724         if (vcr.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
725             throw new RemoteException("Non-OK response verifying a credential we just set: "
726                 + vcr.getResponseCode());
727         }
728         byte[] token = vcr.getPayload();
729         if (token == null) {
730             throw new RemoteException("Empty payload verifying a credential we just set");
731         }
732         changeUserKey(userId, token, secretFromCredential(credential));
733     }
734
735     private void clearUserKeyProtection(int userId) throws RemoteException {
736         changeUserKey(userId, null, null);
737     }
738
739     private static byte[] secretFromCredential(String credential) throws RemoteException {
740         try {
741             MessageDigest digest = MessageDigest.getInstance("SHA-512");
742             // Personalize the hash
743             byte[] personalization = "Android FBE credential hash"
744                     .getBytes(StandardCharsets.UTF_8);
745             // Pad it to the block size of the hash function
746             personalization = Arrays.copyOf(personalization, 128);
747             digest.update(personalization);
748             digest.update(credential.getBytes(StandardCharsets.UTF_8));
749             return digest.digest();
750         } catch (NoSuchAlgorithmException e) {
751             throw new RuntimeException("NoSuchAlgorithmException for SHA-512");
752         }
753     }
754
755     private void changeUserKey(int userId, byte[] token, byte[] secret)
756             throws RemoteException {
757         final UserInfo userInfo = UserManager.get(mContext).getUserInfo(userId);
758         getMountService().changeUserKey(userId, userInfo.serialNumber, token, null, secret);
759     }
760
761     @Override
762     public VerifyCredentialResponse checkPattern(String pattern, int userId) throws RemoteException {
763         return doVerifyPattern(pattern, false, 0, userId);
764     }
765
766     @Override
767     public VerifyCredentialResponse verifyPattern(String pattern, long challenge, int userId)
768             throws RemoteException {
769         return doVerifyPattern(pattern, true, challenge, userId);
770     }
771
772     private VerifyCredentialResponse doVerifyPattern(String pattern, boolean hasChallenge,
773             long challenge, int userId) throws RemoteException {
774        checkPasswordReadPermission(userId);
775        CredentialHash storedHash = mStorage.readPatternHash(userId);
776        boolean shouldReEnrollBaseZero = storedHash != null && storedHash.isBaseZeroPattern;
777
778        String patternToVerify;
779        if (shouldReEnrollBaseZero) {
780            patternToVerify = LockPatternUtils.patternStringToBaseZero(pattern);
781        } else {
782            patternToVerify = pattern;
783        }
784
785        VerifyCredentialResponse response = verifyCredential(userId, storedHash, patternToVerify,
786                hasChallenge, challenge,
787                new CredentialUtil() {
788                    @Override
789                    public void setCredential(String pattern, String oldPattern, int userId)
790                            throws RemoteException {
791                        setLockPattern(pattern, oldPattern, userId);
792                    }
793
794                    @Override
795                    public byte[] toHash(String pattern, int userId) {
796                        return LockPatternUtils.patternToHash(
797                                LockPatternUtils.stringToPattern(pattern));
798                    }
799
800                    @Override
801                    public String adjustForKeystore(String pattern) {
802                        return LockPatternUtils.patternStringToBaseZero(pattern);
803                    }
804                }
805        );
806
807        if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK
808                && shouldReEnrollBaseZero) {
809            setLockPattern(pattern, patternToVerify, userId);
810        }
811
812        return response;
813
814     }
815
816     @Override
817     public VerifyCredentialResponse checkPassword(String password, int userId)
818             throws RemoteException {
819         return doVerifyPassword(password, false, 0, userId);
820     }
821
822     @Override
823     public VerifyCredentialResponse verifyPassword(String password, long challenge, int userId)
824             throws RemoteException {
825         return doVerifyPassword(password, true, challenge, userId);
826     }
827
828     private VerifyCredentialResponse doVerifyPassword(String password, boolean hasChallenge,
829             long challenge, int userId) throws RemoteException {
830        checkPasswordReadPermission(userId);
831        CredentialHash storedHash = mStorage.readPasswordHash(userId);
832        return verifyCredential(userId, storedHash, password, hasChallenge, challenge,
833                new CredentialUtil() {
834                    @Override
835                    public void setCredential(String password, String oldPassword, int userId)
836                            throws RemoteException {
837                        setLockPassword(password, oldPassword, userId);
838                    }
839
840                    @Override
841                    public byte[] toHash(String password, int userId) {
842                        return mLockPatternUtils.passwordToHash(password, userId);
843                    }
844
845                    @Override
846                    public String adjustForKeystore(String password) {
847                        return password;
848                    }
849                }
850        );
851     }
852
853     private VerifyCredentialResponse verifyCredential(int userId, CredentialHash storedHash,
854             String credential, boolean hasChallenge, long challenge, CredentialUtil credentialUtil)
855                 throws RemoteException {
856         if ((storedHash == null || storedHash.hash.length == 0) && TextUtils.isEmpty(credential)) {
857             // don't need to pass empty credentials to GateKeeper
858             return VerifyCredentialResponse.OK;
859         }
860
861         if (TextUtils.isEmpty(credential)) {
862             return VerifyCredentialResponse.ERROR;
863         }
864
865         if (storedHash.version == CredentialHash.VERSION_LEGACY) {
866             byte[] hash = credentialUtil.toHash(credential, userId);
867             if (Arrays.equals(hash, storedHash.hash)) {
868                 unlockKeystore(credentialUtil.adjustForKeystore(credential), userId);
869
870                 // Users with legacy credentials don't have credential-backed
871                 // FBE keys, so just pass through a fake token/secret
872                 Slog.i(TAG, "Unlocking user with fake token: " + userId);
873                 final byte[] fakeToken = String.valueOf(userId).getBytes();
874                 unlockUser(userId, fakeToken, fakeToken);
875
876                 // migrate credential to GateKeeper
877                 credentialUtil.setCredential(credential, null, userId);
878                 if (!hasChallenge) {
879                     return VerifyCredentialResponse.OK;
880                 }
881                 // Fall through to get the auth token. Technically this should never happen,
882                 // as a user that had a legacy credential would have to unlock their device
883                 // before getting to a flow with a challenge, but supporting for consistency.
884             } else {
885                 return VerifyCredentialResponse.ERROR;
886             }
887         }
888
889         VerifyCredentialResponse response;
890         boolean shouldReEnroll = false;
891         GateKeeperResponse gateKeeperResponse = getGateKeeperService()
892                 .verifyChallenge(userId, challenge, storedHash.hash, credential.getBytes());
893         int responseCode = gateKeeperResponse.getResponseCode();
894         if (responseCode == GateKeeperResponse.RESPONSE_RETRY) {
895              response = new VerifyCredentialResponse(gateKeeperResponse.getTimeout());
896         } else if (responseCode == GateKeeperResponse.RESPONSE_OK) {
897             byte[] token = gateKeeperResponse.getPayload();
898             if (token == null) {
899                 // something's wrong if there's no payload with a challenge
900                 Slog.e(TAG, "verifyChallenge response had no associated payload");
901                 response = VerifyCredentialResponse.ERROR;
902             } else {
903                 shouldReEnroll = gateKeeperResponse.getShouldReEnroll();
904                 response = new VerifyCredentialResponse(token);
905             }
906         } else {
907             response = VerifyCredentialResponse.ERROR;
908         }
909
910         if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
911             // credential has matched
912             unlockKeystore(credential, userId);
913
914             Slog.i(TAG, "Unlocking user " + userId +
915                 " with token length " + response.getPayload().length);
916             unlockUser(userId, response.getPayload(), secretFromCredential(credential));
917
918             UserInfo info = UserManager.get(mContext).getUserInfo(userId);
919             if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)) {
920                 TrustManager trustManager =
921                         (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
922                 trustManager.setDeviceLockedForUser(userId, false);
923             }
924             if (shouldReEnroll) {
925                 credentialUtil.setCredential(credential, credential, userId);
926             }
927         } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
928             if (response.getTimeout() > 0) {
929                 requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_LOCKOUT, userId);
930             }
931         }
932
933         return response;
934     }
935
936     @Override
937     public boolean checkVoldPassword(int userId) throws RemoteException {
938         if (!mFirstCallToVold) {
939             return false;
940         }
941         mFirstCallToVold = false;
942
943         checkPasswordReadPermission(userId);
944
945         // There's no guarantee that this will safely connect, but if it fails
946         // we will simply show the lock screen when we shouldn't, so relatively
947         // benign. There is an outside chance something nasty would happen if
948         // this service restarted before vold stales out the password in this
949         // case. The nastiness is limited to not showing the lock screen when
950         // we should, within the first minute of decrypting the phone if this
951         // service can't connect to vold, it restarts, and then the new instance
952         // does successfully connect.
953         final IMountService service = getMountService();
954         String password = service.getPassword();
955         service.clearPassword();
956         if (password == null) {
957             return false;
958         }
959
960         try {
961             if (mLockPatternUtils.isLockPatternEnabled(userId)) {
962                 if (checkPattern(password, userId).getResponseCode()
963                         == GateKeeperResponse.RESPONSE_OK) {
964                     return true;
965                 }
966             }
967         } catch (Exception e) {
968         }
969
970         try {
971             if (mLockPatternUtils.isLockPasswordEnabled(userId)) {
972                 if (checkPassword(password, userId).getResponseCode()
973                         == GateKeeperResponse.RESPONSE_OK) {
974                     return true;
975                 }
976             }
977         } catch (Exception e) {
978         }
979
980         return false;
981     }
982
983     private void removeUser(int userId) {
984         mStorage.removeUser(userId);
985         mStrongAuth.removeUser(userId);
986
987         final KeyStore ks = KeyStore.getInstance();
988         ks.onUserRemoved(userId);
989
990         try {
991             final IGateKeeperService gk = getGateKeeperService();
992             if (gk != null) {
993                     gk.clearSecureUserId(userId);
994             }
995         } catch (RemoteException ex) {
996             Slog.w(TAG, "unable to clear GK secure user id");
997         }
998     }
999
1000     @Override
1001     public void registerStrongAuthTracker(IStrongAuthTracker tracker) {
1002         checkPasswordReadPermission(UserHandle.USER_ALL);
1003         mStrongAuth.registerStrongAuthTracker(tracker);
1004     }
1005
1006     @Override
1007     public void unregisterStrongAuthTracker(IStrongAuthTracker tracker) {
1008         checkPasswordReadPermission(UserHandle.USER_ALL);
1009         mStrongAuth.unregisterStrongAuthTracker(tracker);
1010     }
1011
1012     @Override
1013     public void requireStrongAuth(int strongAuthReason, int userId) {
1014         checkWritePermission(userId);
1015         mStrongAuth.requireStrongAuth(strongAuthReason, userId);
1016     }
1017
1018     private static final String[] VALID_SETTINGS = new String[] {
1019         LockPatternUtils.LOCKOUT_PERMANENT_KEY,
1020         LockPatternUtils.LOCKOUT_ATTEMPT_DEADLINE,
1021         LockPatternUtils.PATTERN_EVER_CHOSEN_KEY,
1022         LockPatternUtils.PASSWORD_TYPE_KEY,
1023         LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY,
1024         LockPatternUtils.LOCK_PASSWORD_SALT_KEY,
1025         LockPatternUtils.DISABLE_LOCKSCREEN_KEY,
1026         LockPatternUtils.LOCKSCREEN_OPTIONS,
1027         LockPatternUtils.LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK,
1028         LockPatternUtils.BIOMETRIC_WEAK_EVER_CHOSEN_KEY,
1029         LockPatternUtils.LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS,
1030         LockPatternUtils.PASSWORD_HISTORY_KEY,
1031         Secure.LOCK_PATTERN_ENABLED,
1032         Secure.LOCK_BIOMETRIC_WEAK_FLAGS,
1033         Secure.LOCK_PATTERN_VISIBLE,
1034         Secure.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED
1035     };
1036
1037     // Reading these settings needs the contacts permission
1038     private static final String[] READ_CONTACTS_PROTECTED_SETTINGS = new String[] {
1039         Secure.LOCK_SCREEN_OWNER_INFO_ENABLED,
1040         Secure.LOCK_SCREEN_OWNER_INFO
1041     };
1042
1043     // Reading these settings needs the same permission as checking the password
1044     private static final String[] READ_PASSWORD_PROTECTED_SETTINGS = new String[] {
1045             LockPatternUtils.LOCK_PASSWORD_SALT_KEY,
1046             LockPatternUtils.PASSWORD_HISTORY_KEY,
1047             LockPatternUtils.PASSWORD_TYPE_KEY,
1048     };
1049
1050     private static final String[] SETTINGS_TO_BACKUP = new String[] {
1051         Secure.LOCK_SCREEN_OWNER_INFO_ENABLED,
1052         Secure.LOCK_SCREEN_OWNER_INFO
1053     };
1054
1055     private IMountService getMountService() {
1056         final IBinder service = ServiceManager.getService("mount");
1057         if (service != null) {
1058             return IMountService.Stub.asInterface(service);
1059         }
1060         return null;
1061     }
1062
1063     private class GateKeeperDiedRecipient implements IBinder.DeathRecipient {
1064         @Override
1065         public void binderDied() {
1066             mGateKeeperService.asBinder().unlinkToDeath(this, 0);
1067             mGateKeeperService = null;
1068         }
1069     }
1070
1071     private synchronized IGateKeeperService getGateKeeperService()
1072             throws RemoteException {
1073         if (mGateKeeperService != null) {
1074             return mGateKeeperService;
1075         }
1076
1077         final IBinder service =
1078             ServiceManager.getService("android.service.gatekeeper.IGateKeeperService");
1079         if (service != null) {
1080             service.linkToDeath(new GateKeeperDiedRecipient(), 0);
1081             mGateKeeperService = IGateKeeperService.Stub.asInterface(service);
1082             return mGateKeeperService;
1083         }
1084
1085         Slog.e(TAG, "Unable to acquire GateKeeperService");
1086         return null;
1087     }
1088 }