blob: ed16af51c7eb0e6a4906166b971c4cd39f8e1436 [file] [log] [blame]
Amith Yamasani52c489c2012-03-28 11:42:42 -07001/*
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
Jeff Sharkey7a96c392012-11-15 14:01:46 -080017package com.android.server;
Amith Yamasani52c489c2012-03-28 11:42:42 -070018
Jeff Sharkey8924e872015-11-30 12:52:10 -070019import android.app.ActivityManagerNative;
Kenny Guyb1b30262016-02-09 16:02:35 +000020import android.app.KeyguardManager;
Jim Miller4f93c582016-01-27 19:05:43 -080021import android.app.Notification;
22import android.app.NotificationManager;
23import android.app.PendingIntent;
Adrian Roos230635e2015-01-07 20:50:29 +010024import android.app.admin.DevicePolicyManager;
Amith Yamasani072543f2015-02-13 11:09:45 -080025import android.app.backup.BackupManager;
Adrian Roosb5e47222015-08-14 15:53:06 -070026import android.app.trust.IStrongAuthTracker;
Clara Bayarri56878a92015-10-29 15:43:55 +000027import android.app.trust.TrustManager;
Robin Leef0246a82014-08-13 09:50:25 +010028import android.content.BroadcastReceiver;
Amith Yamasani52c489c2012-03-28 11:42:42 -070029import android.content.ContentResolver;
Amith Yamasani52c489c2012-03-28 11:42:42 -070030import android.content.Context;
Robin Leef0246a82014-08-13 09:50:25 +010031import android.content.Intent;
32import android.content.IntentFilter;
Jim Miller158fe192013-04-17 15:23:55 -070033import android.content.pm.PackageManager;
Jim Miller187ec582013-04-15 18:27:54 -070034import android.content.pm.UserInfo;
Jim Miller4f93c582016-01-27 19:05:43 -080035import android.content.res.Resources;
36
Adrian Roos261d5ab2014-10-29 14:42:38 +010037import static android.Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE;
Kenny Guyb1b30262016-02-09 16:02:35 +000038import static android.content.Context.KEYGUARD_SERVICE;
Jim Miller187ec582013-04-15 18:27:54 -070039import static android.content.Context.USER_SERVICE;
Svetoslav Ganov6d2c0e52015-06-23 16:33:36 +000040import static android.Manifest.permission.READ_CONTACTS;
Adrian Roos873010d2015-08-25 15:59:00 -070041import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
42
Amith Yamasani52c489c2012-03-28 11:42:42 -070043import android.database.sqlite.SQLiteDatabase;
Amith Yamasani52c489c2012-03-28 11:42:42 -070044import android.os.Binder;
Jeff Sharkeybd91e2f2016-03-22 15:32:31 -060045import android.os.Bundle;
Paul Lawrence945490c2014-03-27 16:37:28 +000046import android.os.IBinder;
Jeff Sharkeybd91e2f2016-03-22 15:32:31 -060047import android.os.IProgressListener;
48import android.os.Parcel;
Amith Yamasani52c489c2012-03-28 11:42:42 -070049import android.os.RemoteException;
Paul Lawrence945490c2014-03-27 16:37:28 +000050import android.os.storage.IMountService;
51import android.os.ServiceManager;
Amith Yamasanid1645f82012-06-12 11:53:26 -070052import android.os.SystemProperties;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070053import android.os.UserHandle;
Jim Miller187ec582013-04-15 18:27:54 -070054import android.os.UserManager;
Amith Yamasani52c489c2012-03-28 11:42:42 -070055import android.provider.Settings;
56import android.provider.Settings.Secure;
Jim Miller187ec582013-04-15 18:27:54 -070057import android.provider.Settings.SettingNotFoundException;
Jim Millerde1af082013-09-11 14:58:26 -070058import android.security.KeyStore;
Andres Morales23974272015-05-14 22:42:26 -070059import android.service.gatekeeper.GateKeeperResponse;
Andres Morales8fa56652015-03-31 09:19:50 -070060import android.service.gatekeeper.IGateKeeperService;
Amith Yamasani52c489c2012-03-28 11:42:42 -070061import android.text.TextUtils;
Jeff Sharkeybd91e2f2016-03-22 15:32:31 -060062import android.util.Log;
Amith Yamasani52c489c2012-03-28 11:42:42 -070063import android.util.Slog;
64
Amith Yamasani072543f2015-02-13 11:09:45 -080065import com.android.internal.util.ArrayUtils;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080066import com.android.internal.widget.ILockSettings;
67import com.android.internal.widget.LockPatternUtils;
Andres Morales23974272015-05-14 22:42:26 -070068import com.android.internal.widget.VerifyCredentialResponse;
Andres Morales8fa56652015-03-31 09:19:50 -070069import com.android.server.LockSettingsStorage.CredentialHash;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080070
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +000071import java.nio.charset.StandardCharsets;
72import java.security.MessageDigest;
73import java.security.NoSuchAlgorithmException;
74
Amith Yamasani52c489c2012-03-28 11:42:42 -070075import java.util.Arrays;
Jim Miller187ec582013-04-15 18:27:54 -070076import java.util.List;
Jeff Sharkeybd91e2f2016-03-22 15:32:31 -060077import java.util.concurrent.CountDownLatch;
78import java.util.concurrent.TimeUnit;
Amith Yamasani52c489c2012-03-28 11:42:42 -070079
80/**
81 * Keeps the lock pattern/password data and related settings for each user.
82 * Used by LockPatternUtils. Needs to be a service because Settings app also needs
83 * to be able to save lockscreen information for secondary users.
84 * @hide
85 */
86public class LockSettingsService extends ILockSettings.Stub {
Amith Yamasani52c489c2012-03-28 11:42:42 -070087 private static final String TAG = "LockSettingsService";
Jim Miller4f93c582016-01-27 19:05:43 -080088 private static final String PERMISSION = ACCESS_KEYGUARD_SECURE_STORAGE;
89 private static final Intent ACTION_NULL; // hack to ensure notification shows the bouncer
90 private static final int FBE_ENCRYPTED_NOTIFICATION = 0;
91 private static final boolean DEBUG = false;
Amith Yamasani52c489c2012-03-28 11:42:42 -070092
Amith Yamasani52c489c2012-03-28 11:42:42 -070093 private final Context mContext;
Adrian Roos261d5ab2014-10-29 14:42:38 +010094 private final LockSettingsStorage mStorage;
Rakesh Iyera7aa4d62016-01-19 17:27:23 -080095 private final LockSettingsStrongAuth mStrongAuth;
Adrian Roos261d5ab2014-10-29 14:42:38 +010096
Jim Millerde1af082013-09-11 14:58:26 -070097 private LockPatternUtils mLockPatternUtils;
Paul Lawrence945490c2014-03-27 16:37:28 +000098 private boolean mFirstCallToVold;
Andres Morales8fa56652015-03-31 09:19:50 -070099 private IGateKeeperService mGateKeeperService;
Jim Miller4f93c582016-01-27 19:05:43 -0800100 private NotificationManager mNotificationManager;
101 private UserManager mUserManager;
102
103 static {
104 // Just launch the home screen, which happens anyway
105 ACTION_NULL = new Intent(Intent.ACTION_MAIN);
106 ACTION_NULL.addCategory(Intent.CATEGORY_HOME);
107 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700108
Andres Morales23974272015-05-14 22:42:26 -0700109 private interface CredentialUtil {
110 void setCredential(String credential, String savedCredential, int userId)
111 throws RemoteException;
112 byte[] toHash(String credential, int userId);
Andres Morales59ef1262015-06-26 13:56:39 -0700113 String adjustForKeystore(String credential);
Andres Morales23974272015-05-14 22:42:26 -0700114 }
115
Jim Miller4f93c582016-01-27 19:05:43 -0800116 // This class manages life cycle events for encrypted users on File Based Encryption (FBE)
117 // devices. The most basic of these is to show/hide notifications about missing features until
118 // the user unlocks the account and credential-encrypted storage is available.
119 public static final class Lifecycle extends SystemService {
120 private LockSettingsService mLockSettingsService;
121
122 public Lifecycle(Context context) {
123 super(context);
124 }
125
126 @Override
127 public void onStart() {
128 mLockSettingsService = new LockSettingsService(getContext());
129 publishBinderService("lock_settings", mLockSettingsService);
130 }
131
132 @Override
133 public void onBootPhase(int phase) {
134 if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
Kenny Guyb1b30262016-02-09 16:02:35 +0000135 mLockSettingsService.maybeShowEncryptionNotifications();
Jim Miller4f93c582016-01-27 19:05:43 -0800136 } else if (phase == SystemService.PHASE_BOOT_COMPLETED) {
137 // TODO
138 }
139 }
140
141 @Override
142 public void onUnlockUser(int userHandle) {
143 mLockSettingsService.onUnlockUser(userHandle);
144 }
145
146 @Override
147 public void onCleanupUser(int userHandle) {
148 mLockSettingsService.onCleanupUser(userHandle);
149 }
150 }
151
Amith Yamasani52c489c2012-03-28 11:42:42 -0700152 public LockSettingsService(Context context) {
153 mContext = context;
Rakesh Iyera7aa4d62016-01-19 17:27:23 -0800154 mStrongAuth = new LockSettingsStrongAuth(context);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700155 // Open the database
Jim Millerde1af082013-09-11 14:58:26 -0700156
157 mLockPatternUtils = new LockPatternUtils(context);
Paul Lawrence945490c2014-03-27 16:37:28 +0000158 mFirstCallToVold = true;
Robin Leef0246a82014-08-13 09:50:25 +0100159
160 IntentFilter filter = new IntentFilter();
161 filter.addAction(Intent.ACTION_USER_ADDED);
Adrian Roos3dcae682014-10-29 14:43:56 +0100162 filter.addAction(Intent.ACTION_USER_STARTING);
Adrian Roosdb0f76e2015-01-07 22:19:38 +0100163 filter.addAction(Intent.ACTION_USER_REMOVED);
Adrian Roosb5e47222015-08-14 15:53:06 -0700164 filter.addAction(Intent.ACTION_USER_PRESENT);
Robin Leef0246a82014-08-13 09:50:25 +0100165 mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
Adrian Roos261d5ab2014-10-29 14:42:38 +0100166
167 mStorage = new LockSettingsStorage(context, new LockSettingsStorage.Callback() {
168 @Override
169 public void initialize(SQLiteDatabase db) {
170 // Get the lockscreen default from a system property, if available
171 boolean lockScreenDisable = SystemProperties.getBoolean(
172 "ro.lockscreen.disable.default", false);
173 if (lockScreenDisable) {
174 mStorage.writeKeyValue(db, LockPatternUtils.DISABLE_LOCKSCREEN_KEY, "1", 0);
175 }
176 }
177 });
Jim Miller4f93c582016-01-27 19:05:43 -0800178 mNotificationManager = (NotificationManager)
179 mContext.getSystemService(Context.NOTIFICATION_SERVICE);
180 mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
181 }
182
183 /**
184 * If the account is credential-encrypted, show notification requesting the user to unlock
185 * the device.
186 */
Kenny Guyb1b30262016-02-09 16:02:35 +0000187 private void maybeShowEncryptionNotifications() {
188 final List<UserInfo> users = mUserManager.getUsers();
189 for (int i = 0; i < users.size(); i++) {
190 UserInfo user = users.get(i);
191 UserHandle userHandle = user.getUserHandle();
192 if (!mUserManager.isUserUnlocked(userHandle)) {
193 if (!user.isManagedProfile()) {
194 showEncryptionNotification(userHandle);
195 } else {
196 UserInfo parent = mUserManager.getProfileParent(user.id);
197 if (parent != null && mUserManager.isUserUnlocked(parent.getUserHandle())) {
198 // Only show notifications for managed profiles once their parent
199 // user is unlocked.
200 showEncryptionNotificationForProfile(userHandle);
201 }
Jim Miller4f93c582016-01-27 19:05:43 -0800202 }
203 }
Jim Miller4f93c582016-01-27 19:05:43 -0800204 }
205 }
206
Kenny Guyb1b30262016-02-09 16:02:35 +0000207 private void showEncryptionNotificationForProfile(UserHandle user) {
208 Resources r = mContext.getResources();
209 CharSequence title = r.getText(
210 com.android.internal.R.string.user_encrypted_title);
211 CharSequence message = r.getText(
212 com.android.internal.R.string.profile_encrypted_message);
213 CharSequence detail = r.getText(
214 com.android.internal.R.string.profile_encrypted_detail);
215
216 final KeyguardManager km = (KeyguardManager) mContext.getSystemService(KEYGUARD_SERVICE);
217 final Intent unlockIntent = km.createConfirmDeviceCredentialIntent(null, null, user.getIdentifier());
218 if (unlockIntent == null) {
219 return;
220 }
221 unlockIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
222 PendingIntent intent = PendingIntent.getActivity(mContext, 0, unlockIntent,
223 PendingIntent.FLAG_UPDATE_CURRENT);
224
225 showEncryptionNotification(user, title, message, detail, intent);
226 }
227
Jim Miller4f93c582016-01-27 19:05:43 -0800228 private void showEncryptionNotification(UserHandle user) {
Jim Miller4f93c582016-01-27 19:05:43 -0800229 Resources r = mContext.getResources();
230 CharSequence title = r.getText(
231 com.android.internal.R.string.user_encrypted_title);
232 CharSequence message = r.getText(
233 com.android.internal.R.string.user_encrypted_message);
234 CharSequence detail = r.getText(
235 com.android.internal.R.string.user_encrypted_detail);
236
237 PendingIntent intent = PendingIntent.getBroadcast(mContext, 0, ACTION_NULL,
238 PendingIntent.FLAG_UPDATE_CURRENT);
239
Kenny Guyb1b30262016-02-09 16:02:35 +0000240 showEncryptionNotification(user, title, message, detail, intent);
241 }
242
243 private void showEncryptionNotification(UserHandle user, CharSequence title, CharSequence message,
244 CharSequence detail, PendingIntent intent) {
245 if (DEBUG) Slog.v(TAG, "showing encryption notification, user: " + user.getIdentifier());
Jim Miller4f93c582016-01-27 19:05:43 -0800246 Notification notification = new Notification.Builder(mContext)
Jim Millerb1135b72016-02-02 17:08:56 -0800247 .setSmallIcon(com.android.internal.R.drawable.ic_user_secure)
Jim Miller4f93c582016-01-27 19:05:43 -0800248 .setWhen(0)
249 .setOngoing(true)
250 .setTicker(title)
251 .setDefaults(0) // please be quiet
252 .setPriority(Notification.PRIORITY_MAX)
253 .setColor(mContext.getColor(
254 com.android.internal.R.color.system_notification_accent_color))
255 .setContentTitle(title)
256 .setContentText(message)
257 .setContentInfo(detail)
258 .setVisibility(Notification.VISIBILITY_PUBLIC)
259 .setContentIntent(intent)
260 .build();
261 mNotificationManager.notifyAsUser(null, FBE_ENCRYPTED_NOTIFICATION, notification, user);
262 }
263
264 public void hideEncryptionNotification(UserHandle userHandle) {
265 if (DEBUG) Slog.v(TAG, "hide encryption notification, user: "+ userHandle.getIdentifier());
266 mNotificationManager.cancelAsUser(null, FBE_ENCRYPTED_NOTIFICATION, userHandle);
267 }
268
269 public void onCleanupUser(int userId) {
270 hideEncryptionNotification(new UserHandle(userId));
271 }
272
Kenny Guyb1b30262016-02-09 16:02:35 +0000273 public void onUnlockUser(int userId) {
274 hideEncryptionNotification(new UserHandle(userId));
275
276 // Now we have unlocked the parent user we should show notifications
277 // about any profiles that exist.
278 List<UserInfo> profiles = mUserManager.getProfiles(userId);
279 for (int i = 0; i < profiles.size(); i++) {
280 UserInfo profile = profiles.get(i);
281 if (profile.isManagedProfile()) {
282 UserHandle userHandle = profile.getUserHandle();
283 if (!mUserManager.isUserUnlocked(userHandle)) {
284 showEncryptionNotificationForProfile(userHandle);
285 }
286 }
287 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700288 }
289
Robin Leef0246a82014-08-13 09:50:25 +0100290 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
291 @Override
292 public void onReceive(Context context, Intent intent) {
Robin Lee1096cf82014-09-01 16:52:47 +0100293 if (Intent.ACTION_USER_ADDED.equals(intent.getAction())) {
Chad Brubaker83ce0952015-05-12 13:00:02 -0700294 // Notify keystore that a new user was added.
Robin Leef0246a82014-08-13 09:50:25 +0100295 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
Robin Lee49d810c2014-09-23 13:50:22 +0100296 final KeyStore ks = KeyStore.getInstance();
Robin Leef0246a82014-08-13 09:50:25 +0100297 final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
298 final UserInfo parentInfo = um.getProfileParent(userHandle);
Chad Brubaker83ce0952015-05-12 13:00:02 -0700299 final int parentHandle = parentInfo != null ? parentInfo.id : -1;
300 ks.onUserAdded(userHandle, parentHandle);
Adrian Roos3dcae682014-10-29 14:43:56 +0100301 } else if (Intent.ACTION_USER_STARTING.equals(intent.getAction())) {
302 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
303 mStorage.prefetchUser(userHandle);
Adrian Roosb5e47222015-08-14 15:53:06 -0700304 } else if (Intent.ACTION_USER_PRESENT.equals(intent.getAction())) {
305 mStrongAuth.reportUnlock(getSendingUserId());
Adrian Roosdb0f76e2015-01-07 22:19:38 +0100306 } else if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
307 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
308 if (userHandle > 0) {
309 removeUser(userHandle);
310 }
Robin Leef0246a82014-08-13 09:50:25 +0100311 }
312 }
313 };
314
Jim Miller4f93c582016-01-27 19:05:43 -0800315 @Override // binder interface
Amith Yamasani52c489c2012-03-28 11:42:42 -0700316 public void systemReady() {
317 migrateOldData();
Andres Morales301ea442015-04-17 09:15:47 -0700318 try {
319 getGateKeeperService();
320 } catch (RemoteException e) {
321 Slog.e(TAG, "Failure retrieving IGateKeeperService", e);
322 }
Xiaohui Chen7c696362015-09-16 09:56:14 -0700323 // TODO: maybe skip this for split system user mode.
324 mStorage.prefetchUser(UserHandle.USER_SYSTEM);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700325 }
326
327 private void migrateOldData() {
328 try {
Jim Miller187ec582013-04-15 18:27:54 -0700329 // These Settings moved before multi-user was enabled, so we only have to do it for the
330 // root user.
331 if (getString("migrated", null, 0) == null) {
332 final ContentResolver cr = mContext.getContentResolver();
333 for (String validSetting : VALID_SETTINGS) {
334 String value = Settings.Secure.getString(cr, validSetting);
335 if (value != null) {
336 setString(validSetting, value, 0);
337 }
338 }
339 // No need to move the password / pattern files. They're already in the right place.
340 setString("migrated", "true", 0);
341 Slog.i(TAG, "Migrated lock settings to new location");
Amith Yamasani52c489c2012-03-28 11:42:42 -0700342 }
343
Jim Miller187ec582013-04-15 18:27:54 -0700344 // These Settings changed after multi-user was enabled, hence need to be moved per user.
345 if (getString("migrated_user_specific", null, 0) == null) {
346 final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
347 final ContentResolver cr = mContext.getContentResolver();
348 List<UserInfo> users = um.getUsers();
349 for (int user = 0; user < users.size(); user++) {
Jim Miller2d8ecf9d2013-04-22 17:17:03 -0700350 // Migrate owner info
351 final int userId = users.get(user).id;
352 final String OWNER_INFO = Secure.LOCK_SCREEN_OWNER_INFO;
353 String ownerInfo = Settings.Secure.getStringForUser(cr, OWNER_INFO, userId);
Jim Miller325c5672016-03-01 19:21:47 -0800354 if (!TextUtils.isEmpty(ownerInfo)) {
Jim Miller2d8ecf9d2013-04-22 17:17:03 -0700355 setString(OWNER_INFO, ownerInfo, userId);
Jim Miller325c5672016-03-01 19:21:47 -0800356 Settings.Secure.putStringForUser(cr, OWNER_INFO, "", userId);
Jim Miller2d8ecf9d2013-04-22 17:17:03 -0700357 }
Jim Miller187ec582013-04-15 18:27:54 -0700358
Jim Miller2d8ecf9d2013-04-22 17:17:03 -0700359 // Migrate owner info enabled. Note there was a bug where older platforms only
360 // stored this value if the checkbox was toggled at least once. The code detects
361 // this case by handling the exception.
362 final String OWNER_INFO_ENABLED = Secure.LOCK_SCREEN_OWNER_INFO_ENABLED;
363 boolean enabled;
364 try {
365 int ivalue = Settings.Secure.getIntForUser(cr, OWNER_INFO_ENABLED, userId);
366 enabled = ivalue != 0;
367 setLong(OWNER_INFO_ENABLED, enabled ? 1 : 0, userId);
368 } catch (SettingNotFoundException e) {
369 // Setting was never stored. Store it if the string is not empty.
370 if (!TextUtils.isEmpty(ownerInfo)) {
371 setLong(OWNER_INFO_ENABLED, 1, userId);
Jim Miller187ec582013-04-15 18:27:54 -0700372 }
373 }
Jim Miller2d8ecf9d2013-04-22 17:17:03 -0700374 Settings.Secure.putIntForUser(cr, OWNER_INFO_ENABLED, 0, userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700375 }
Jim Miller187ec582013-04-15 18:27:54 -0700376 // No need to move the password / pattern files. They're already in the right place.
377 setString("migrated_user_specific", "true", 0);
378 Slog.i(TAG, "Migrated per-user lock settings to new location");
Amith Yamasani52c489c2012-03-28 11:42:42 -0700379 }
Adrian Roos230635e2015-01-07 20:50:29 +0100380
381 // Migrates biometric weak such that the fallback mechanism becomes the primary.
382 if (getString("migrated_biometric_weak", null, 0) == null) {
383 final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
384 List<UserInfo> users = um.getUsers();
385 for (int i = 0; i < users.size(); i++) {
386 int userId = users.get(i).id;
387 long type = getLong(LockPatternUtils.PASSWORD_TYPE_KEY,
388 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
389 userId);
390 long alternateType = getLong(LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY,
391 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
392 userId);
393 if (type == DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK) {
394 setLong(LockPatternUtils.PASSWORD_TYPE_KEY,
395 alternateType,
396 userId);
397 }
398 setLong(LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY,
399 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
400 userId);
401 }
402 setString("migrated_biometric_weak", "true", 0);
403 Slog.i(TAG, "Migrated biometric weak to use the fallback instead");
404 }
Adrian Roos43830582015-04-21 16:04:43 -0700405
406 // Migrates lockscreen.disabled. Prior to M, the flag was ignored when more than one
407 // user was present on the system, so if we're upgrading to M and there is more than one
408 // user we disable the flag to remain consistent.
409 if (getString("migrated_lockscreen_disabled", null, 0) == null) {
410 final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
411
412 final List<UserInfo> users = um.getUsers();
413 final int userCount = users.size();
414 int switchableUsers = 0;
415 for (int i = 0; i < userCount; i++) {
416 if (users.get(i).supportsSwitchTo()) {
417 switchableUsers++;
418 }
419 }
420
421 if (switchableUsers > 1) {
422 for (int i = 0; i < userCount; i++) {
423 int id = users.get(i).id;
424
425 if (getBoolean(LockPatternUtils.DISABLE_LOCKSCREEN_KEY, false, id)) {
426 setBoolean(LockPatternUtils.DISABLE_LOCKSCREEN_KEY, false, id);
427 }
428 }
429 }
430
431 setString("migrated_lockscreen_disabled", "true", 0);
432 Slog.i(TAG, "Migrated lockscreen disabled flag");
433 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700434 } catch (RemoteException re) {
Jim Miller187ec582013-04-15 18:27:54 -0700435 Slog.e(TAG, "Unable to migrate old data", re);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700436 }
437 }
438
Jim Miller5ecd8112013-01-09 18:50:26 -0800439 private final void checkWritePermission(int userId) {
Jim Miller505329b2013-11-08 13:25:36 -0800440 mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsWrite");
Amith Yamasani52c489c2012-03-28 11:42:42 -0700441 }
442
Jim Miller5ecd8112013-01-09 18:50:26 -0800443 private final void checkPasswordReadPermission(int userId) {
Jim Miller505329b2013-11-08 13:25:36 -0800444 mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsRead");
Amith Yamasani52c489c2012-03-28 11:42:42 -0700445 }
446
Jim Miller158fe192013-04-17 15:23:55 -0700447 private final void checkReadPermission(String requestedKey, int userId) {
Amith Yamasani52c489c2012-03-28 11:42:42 -0700448 final int callingUid = Binder.getCallingUid();
Adrian Roos001b00d2015-02-24 17:08:48 +0100449
Svetoslav Ganov6d2c0e52015-06-23 16:33:36 +0000450 for (int i = 0; i < READ_CONTACTS_PROTECTED_SETTINGS.length; i++) {
451 String key = READ_CONTACTS_PROTECTED_SETTINGS[i];
452 if (key.equals(requestedKey) && mContext.checkCallingOrSelfPermission(READ_CONTACTS)
Jim Miller158fe192013-04-17 15:23:55 -0700453 != PackageManager.PERMISSION_GRANTED) {
454 throw new SecurityException("uid=" + callingUid
Svetoslav Ganov6d2c0e52015-06-23 16:33:36 +0000455 + " needs permission " + READ_CONTACTS + " to read "
Jim Miller158fe192013-04-17 15:23:55 -0700456 + requestedKey + " for user " + userId);
457 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700458 }
Adrian Roos001b00d2015-02-24 17:08:48 +0100459
460 for (int i = 0; i < READ_PASSWORD_PROTECTED_SETTINGS.length; i++) {
461 String key = READ_PASSWORD_PROTECTED_SETTINGS[i];
462 if (key.equals(requestedKey) && mContext.checkCallingOrSelfPermission(PERMISSION)
463 != PackageManager.PERMISSION_GRANTED) {
464 throw new SecurityException("uid=" + callingUid
465 + " needs permission " + PERMISSION + " to read "
466 + requestedKey + " for user " + userId);
467 }
468 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700469 }
470
471 @Override
472 public void setBoolean(String key, boolean value, int userId) throws RemoteException {
473 checkWritePermission(userId);
Adrian Roos261d5ab2014-10-29 14:42:38 +0100474 setStringUnchecked(key, userId, value ? "1" : "0");
Amith Yamasani52c489c2012-03-28 11:42:42 -0700475 }
476
477 @Override
478 public void setLong(String key, long value, int userId) throws RemoteException {
479 checkWritePermission(userId);
Adrian Roos261d5ab2014-10-29 14:42:38 +0100480 setStringUnchecked(key, userId, Long.toString(value));
Amith Yamasani52c489c2012-03-28 11:42:42 -0700481 }
482
483 @Override
484 public void setString(String key, String value, int userId) throws RemoteException {
485 checkWritePermission(userId);
Adrian Roos261d5ab2014-10-29 14:42:38 +0100486 setStringUnchecked(key, userId, value);
487 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700488
Adrian Roos261d5ab2014-10-29 14:42:38 +0100489 private void setStringUnchecked(String key, int userId, String value) {
490 mStorage.writeKeyValue(key, value, userId);
Amith Yamasani072543f2015-02-13 11:09:45 -0800491 if (ArrayUtils.contains(SETTINGS_TO_BACKUP, key)) {
492 BackupManager.dataChanged("com.android.providers.settings");
493 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700494 }
495
496 @Override
497 public boolean getBoolean(String key, boolean defaultValue, int userId) throws RemoteException {
Jim Miller158fe192013-04-17 15:23:55 -0700498 checkReadPermission(key, userId);
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100499 String value = getStringUnchecked(key, null, userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700500 return TextUtils.isEmpty(value) ?
501 defaultValue : (value.equals("1") || value.equals("true"));
502 }
503
504 @Override
505 public long getLong(String key, long defaultValue, int userId) throws RemoteException {
Jim Miller158fe192013-04-17 15:23:55 -0700506 checkReadPermission(key, userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700507
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100508 String value = getStringUnchecked(key, null, userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700509 return TextUtils.isEmpty(value) ? defaultValue : Long.parseLong(value);
510 }
511
512 @Override
513 public String getString(String key, String defaultValue, int userId) throws RemoteException {
Jim Miller158fe192013-04-17 15:23:55 -0700514 checkReadPermission(key, userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700515
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100516 return getStringUnchecked(key, defaultValue, userId);
517 }
518
519 public String getStringUnchecked(String key, String defaultValue, int userId) {
520 if (Settings.Secure.LOCK_PATTERN_ENABLED.equals(key)) {
Adrian Roos7811d9f2015-07-27 15:10:13 -0700521 long ident = Binder.clearCallingIdentity();
522 try {
523 return mLockPatternUtils.isLockPatternEnabled(userId) ? "1" : "0";
524 } finally {
525 Binder.restoreCallingIdentity(ident);
526 }
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100527 }
528
Bryce Lee46145962015-12-14 14:39:10 -0800529 if (LockPatternUtils.LEGACY_LOCK_PATTERN_ENABLED.equals(key)) {
530 key = Settings.Secure.LOCK_PATTERN_ENABLED;
531 }
532
Adrian Roos261d5ab2014-10-29 14:42:38 +0100533 return mStorage.readKeyValue(key, defaultValue, userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700534 }
535
Adrian Roos4f788452014-05-22 20:45:59 +0200536 @Override
Amith Yamasani52c489c2012-03-28 11:42:42 -0700537 public boolean havePassword(int userId) throws RemoteException {
538 // Do we need a permissions check here?
539
Adrian Roos261d5ab2014-10-29 14:42:38 +0100540 return mStorage.hasPassword(userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700541 }
542
543 @Override
544 public boolean havePattern(int userId) throws RemoteException {
545 // Do we need a permissions check here?
546
Adrian Roos261d5ab2014-10-29 14:42:38 +0100547 return mStorage.hasPattern(userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700548 }
549
Chad Brubakera91a8502015-05-07 10:02:22 -0700550 private void setKeystorePassword(String password, int userHandle) {
Robin Leef0246a82014-08-13 09:50:25 +0100551 final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
552 final KeyStore ks = KeyStore.getInstance();
553
Clara Bayarri0a587d22016-02-23 14:49:41 -0800554 if (um.getUserInfo(userHandle).isManagedProfile()) {
555 if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userHandle)) {
556 ks.onUserPasswordChanged(userHandle, password);
557 } else {
558 throw new RuntimeException("Can't set keystore password on a profile that "
559 + "doesn't have a profile challenge.");
560 }
561 } else {
562 final List<UserInfo> profiles = um.getProfiles(userHandle);
563 for (UserInfo pi : profiles) {
564 // Change password on the given user and all its profiles that don't have
565 // their own profile challenge enabled.
566 if (pi.id == userHandle || (pi.isManagedProfile()
567 && !mLockPatternUtils.isSeparateProfileChallengeEnabled(pi.id))) {
568 ks.onUserPasswordChanged(pi.id, password);
569 }
570 }
Chad Brubakera91a8502015-05-07 10:02:22 -0700571 }
572 }
573
574 private void unlockKeystore(String password, int userHandle) {
575 final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
576 final KeyStore ks = KeyStore.getInstance();
577
Clara Bayarri0a587d22016-02-23 14:49:41 -0800578 if (um.getUserInfo(userHandle).isManagedProfile()) {
579 if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userHandle)) {
580 ks.unlock(userHandle, password);
581 } else {
582 throw new RuntimeException("Can't unlock a profile explicitly if it "
583 + "doesn't have a profile challenge.");
584 }
585 } else {
586 final List<UserInfo> profiles = um.getProfiles(userHandle);
587 for (UserInfo pi : profiles) {
588 // Unlock the given user and all its profiles that don't have
589 // their own profile challenge enabled.
590 if (pi.id == userHandle || (pi.isManagedProfile()
591 && !mLockPatternUtils.isSeparateProfileChallengeEnabled(pi.id))) {
592 ks.unlock(pi.id, password);
593 }
594 }
Jim Millerde1af082013-09-11 14:58:26 -0700595 }
596 }
597
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +0000598 private void unlockUser(int userId, byte[] token, byte[] secret) {
Jeff Sharkeybd91e2f2016-03-22 15:32:31 -0600599 // TODO: make this method fully async so we can update UI with progress strings
600 final CountDownLatch latch = new CountDownLatch(1);
601 final IProgressListener listener = new IProgressListener.Stub() {
602 @Override
603 public void onStarted(int id, Bundle extras) throws RemoteException {
604 // Ignored
605 }
606
607 @Override
608 public void onProgress(int id, int progress, Bundle extras) throws RemoteException {
609 // Ignored
610 }
611
612 @Override
613 public void onFinished(int id, Bundle extras) throws RemoteException {
614 Log.d(TAG, "unlockUser finished!");
615 latch.countDown();
616 }
617 };
618
Jeff Sharkey8924e872015-11-30 12:52:10 -0700619 try {
Jeff Sharkeybd91e2f2016-03-22 15:32:31 -0600620 ActivityManagerNative.getDefault().unlockUser(userId, token, secret, listener);
Jeff Sharkey8924e872015-11-30 12:52:10 -0700621 } catch (RemoteException e) {
622 throw e.rethrowAsRuntimeException();
623 }
Jeff Sharkeybd91e2f2016-03-22 15:32:31 -0600624
625 try {
626 latch.await(15, TimeUnit.SECONDS);
627 } catch (InterruptedException e) {
628 Thread.currentThread().interrupt();
629 }
Jeff Sharkey8924e872015-11-30 12:52:10 -0700630 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700631
Andres Morales8fa56652015-03-31 09:19:50 -0700632 private byte[] getCurrentHandle(int userId) {
633 CredentialHash credential;
634 byte[] currentHandle;
Jim Millerde1af082013-09-11 14:58:26 -0700635
Andres Morales8fa56652015-03-31 09:19:50 -0700636 int currentHandleType = mStorage.getStoredCredentialType(userId);
637 switch (currentHandleType) {
638 case CredentialHash.TYPE_PATTERN:
639 credential = mStorage.readPatternHash(userId);
640 currentHandle = credential != null
641 ? credential.hash
642 : null;
643 break;
644 case CredentialHash.TYPE_PASSWORD:
645 credential = mStorage.readPasswordHash(userId);
646 currentHandle = credential != null
647 ? credential.hash
648 : null;
649 break;
650 case CredentialHash.TYPE_NONE:
651 default:
652 currentHandle = null;
653 break;
654 }
655
656 // sanity check
657 if (currentHandleType != CredentialHash.TYPE_NONE && currentHandle == null) {
658 Slog.e(TAG, "Stored handle type [" + currentHandleType + "] but no handle available");
659 }
660
661 return currentHandle;
Amith Yamasani52c489c2012-03-28 11:42:42 -0700662 }
663
Andres Morales8fa56652015-03-31 09:19:50 -0700664
Amith Yamasani52c489c2012-03-28 11:42:42 -0700665 @Override
Andres Morales8fa56652015-03-31 09:19:50 -0700666 public void setLockPattern(String pattern, String savedCredential, int userId)
667 throws RemoteException {
668 byte[] currentHandle = getCurrentHandle(userId);
669
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700670 if (pattern == null) {
Andres Moralescfb61602015-04-16 16:31:15 -0700671 getGateKeeperService().clearSecureUserId(userId);
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700672 mStorage.writePatternHash(null, userId);
Chad Brubakera91a8502015-05-07 10:02:22 -0700673 setKeystorePassword(null, userId);
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +0000674 clearUserKeyProtection(userId);
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700675 return;
676 }
677
Andres Morales8fa56652015-03-31 09:19:50 -0700678 if (currentHandle == null) {
679 if (savedCredential != null) {
680 Slog.w(TAG, "Saved credential provided, but none stored");
681 }
682 savedCredential = null;
683 }
684
685 byte[] enrolledHandle = enrollCredential(currentHandle, savedCredential, pattern, userId);
686 if (enrolledHandle != null) {
687 mStorage.writePatternHash(enrolledHandle, userId);
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +0000688 setUserKeyProtection(userId, pattern, verifyPattern(pattern, 0, userId));
Andres Morales8fa56652015-03-31 09:19:50 -0700689 } else {
Andres Morales2c4a5732015-07-09 16:11:00 -0700690 throw new RemoteException("Failed to enroll pattern");
Andres Morales8fa56652015-03-31 09:19:50 -0700691 }
692 }
693
694
695 @Override
696 public void setLockPassword(String password, String savedCredential, int userId)
697 throws RemoteException {
Andres Morales8fa56652015-03-31 09:19:50 -0700698 byte[] currentHandle = getCurrentHandle(userId);
699
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700700 if (password == null) {
Andres Moralescfb61602015-04-16 16:31:15 -0700701 getGateKeeperService().clearSecureUserId(userId);
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700702 mStorage.writePasswordHash(null, userId);
Chad Brubakera91a8502015-05-07 10:02:22 -0700703 setKeystorePassword(null, userId);
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +0000704 clearUserKeyProtection(userId);
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700705 return;
706 }
707
Andres Morales8fa56652015-03-31 09:19:50 -0700708 if (currentHandle == null) {
709 if (savedCredential != null) {
710 Slog.w(TAG, "Saved credential provided, but none stored");
711 }
712 savedCredential = null;
713 }
714
715 byte[] enrolledHandle = enrollCredential(currentHandle, savedCredential, password, userId);
716 if (enrolledHandle != null) {
717 mStorage.writePasswordHash(enrolledHandle, userId);
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +0000718 setUserKeyProtection(userId, password, verifyPassword(password, 0, userId));
Andres Morales8fa56652015-03-31 09:19:50 -0700719 } else {
Andres Morales2c4a5732015-07-09 16:11:00 -0700720 throw new RemoteException("Failed to enroll password");
Andres Morales8fa56652015-03-31 09:19:50 -0700721 }
722 }
723
724 private byte[] enrollCredential(byte[] enrolledHandle,
725 String enrolledCredential, String toEnroll, int userId)
726 throws RemoteException {
Jim Millerde1af082013-09-11 14:58:26 -0700727 checkWritePermission(userId);
Andres Morales8fa56652015-03-31 09:19:50 -0700728 byte[] enrolledCredentialBytes = enrolledCredential == null
729 ? null
730 : enrolledCredential.getBytes();
731 byte[] toEnrollBytes = toEnroll == null
732 ? null
733 : toEnroll.getBytes();
Andres Morales23974272015-05-14 22:42:26 -0700734 GateKeeperResponse response = getGateKeeperService().enroll(userId, enrolledHandle,
735 enrolledCredentialBytes, toEnrollBytes);
Jim Millerde1af082013-09-11 14:58:26 -0700736
Andres Morales23974272015-05-14 22:42:26 -0700737 if (response == null) {
738 return null;
Andres Morales8fa56652015-03-31 09:19:50 -0700739 }
Jim Millerde1af082013-09-11 14:58:26 -0700740
Andres Morales23974272015-05-14 22:42:26 -0700741 byte[] hash = response.getPayload();
742 if (hash != null) {
743 setKeystorePassword(toEnroll, userId);
744 } else {
745 // Should not happen
746 Slog.e(TAG, "Throttled while enrolling a password");
747 }
Andres Morales8fa56652015-03-31 09:19:50 -0700748 return hash;
Jim Millerde1af082013-09-11 14:58:26 -0700749 }
750
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +0000751 private void setUserKeyProtection(int userId, String credential, VerifyCredentialResponse vcr)
752 throws RemoteException {
753 if (vcr == null) {
754 throw new RemoteException("Null response verifying a credential we just set");
755 }
756 if (vcr.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
757 throw new RemoteException("Non-OK response verifying a credential we just set: "
758 + vcr.getResponseCode());
759 }
760 byte[] token = vcr.getPayload();
761 if (token == null) {
762 throw new RemoteException("Empty payload verifying a credential we just set");
763 }
764 changeUserKey(userId, token, secretFromCredential(credential));
765 }
766
767 private void clearUserKeyProtection(int userId) throws RemoteException {
768 changeUserKey(userId, null, null);
769 }
770
771 private static byte[] secretFromCredential(String credential) throws RemoteException {
772 try {
773 MessageDigest digest = MessageDigest.getInstance("SHA-512");
774 // Personalize the hash
775 byte[] personalization = "Android FBE credential hash"
776 .getBytes(StandardCharsets.UTF_8);
777 // Pad it to the block size of the hash function
778 personalization = Arrays.copyOf(personalization, 128);
779 digest.update(personalization);
780 digest.update(credential.getBytes(StandardCharsets.UTF_8));
781 return digest.digest();
782 } catch (NoSuchAlgorithmException e) {
783 throw new RuntimeException("NoSuchAlgorithmException for SHA-512");
784 }
785 }
786
787 private void changeUserKey(int userId, byte[] token, byte[] secret)
788 throws RemoteException {
789 final UserInfo userInfo = UserManager.get(mContext).getUserInfo(userId);
790 getMountService().changeUserKey(userId, userInfo.serialNumber, token, null, secret);
791 }
792
Jim Millerde1af082013-09-11 14:58:26 -0700793 @Override
Andres Morales23974272015-05-14 22:42:26 -0700794 public VerifyCredentialResponse checkPattern(String pattern, int userId) throws RemoteException {
795 return doVerifyPattern(pattern, false, 0, userId);
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700796 }
Adrian Roos261d5ab2014-10-29 14:42:38 +0100797
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700798 @Override
Andres Morales23974272015-05-14 22:42:26 -0700799 public VerifyCredentialResponse verifyPattern(String pattern, long challenge, int userId)
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700800 throws RemoteException {
Andres Morales23974272015-05-14 22:42:26 -0700801 return doVerifyPattern(pattern, true, challenge, userId);
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700802 }
803
Andres Moralese40bad82015-05-28 14:21:36 -0700804 private VerifyCredentialResponse doVerifyPattern(String pattern, boolean hasChallenge,
805 long challenge, int userId) throws RemoteException {
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700806 checkPasswordReadPermission(userId);
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700807 CredentialHash storedHash = mStorage.readPatternHash(userId);
Andres Moralese40bad82015-05-28 14:21:36 -0700808 boolean shouldReEnrollBaseZero = storedHash != null && storedHash.isBaseZeroPattern;
809
810 String patternToVerify;
811 if (shouldReEnrollBaseZero) {
812 patternToVerify = LockPatternUtils.patternStringToBaseZero(pattern);
813 } else {
814 patternToVerify = pattern;
815 }
816
817 VerifyCredentialResponse response = verifyCredential(userId, storedHash, patternToVerify,
818 hasChallenge, challenge,
Andres Morales23974272015-05-14 22:42:26 -0700819 new CredentialUtil() {
820 @Override
821 public void setCredential(String pattern, String oldPattern, int userId)
822 throws RemoteException {
823 setLockPattern(pattern, oldPattern, userId);
824 }
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700825
Andres Morales23974272015-05-14 22:42:26 -0700826 @Override
827 public byte[] toHash(String pattern, int userId) {
Andres Moralese40bad82015-05-28 14:21:36 -0700828 return LockPatternUtils.patternToHash(
829 LockPatternUtils.stringToPattern(pattern));
Andres Morales23974272015-05-14 22:42:26 -0700830 }
Andres Morales59ef1262015-06-26 13:56:39 -0700831
832 @Override
833 public String adjustForKeystore(String pattern) {
834 return LockPatternUtils.patternStringToBaseZero(pattern);
835 }
Andres Morales23974272015-05-14 22:42:26 -0700836 }
837 );
Andres Moralese40bad82015-05-28 14:21:36 -0700838
839 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK
840 && shouldReEnrollBaseZero) {
841 setLockPattern(pattern, patternToVerify, userId);
842 }
843
844 return response;
845
Amith Yamasani52c489c2012-03-28 11:42:42 -0700846 }
847
848 @Override
Andres Morales23974272015-05-14 22:42:26 -0700849 public VerifyCredentialResponse checkPassword(String password, int userId)
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700850 throws RemoteException {
Andres Morales23974272015-05-14 22:42:26 -0700851 return doVerifyPassword(password, false, 0, userId);
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700852 }
853
Andres Morales23974272015-05-14 22:42:26 -0700854 @Override
855 public VerifyCredentialResponse verifyPassword(String password, long challenge, int userId)
856 throws RemoteException {
857 return doVerifyPassword(password, true, challenge, userId);
858 }
859
860 private VerifyCredentialResponse doVerifyPassword(String password, boolean hasChallenge,
861 long challenge, int userId) throws RemoteException {
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700862 checkPasswordReadPermission(userId);
Andres Morales8fa56652015-03-31 09:19:50 -0700863 CredentialHash storedHash = mStorage.readPasswordHash(userId);
Andres Morales23974272015-05-14 22:42:26 -0700864 return verifyCredential(userId, storedHash, password, hasChallenge, challenge,
865 new CredentialUtil() {
866 @Override
867 public void setCredential(String password, String oldPassword, int userId)
868 throws RemoteException {
869 setLockPassword(password, oldPassword, userId);
870 }
Adrian Roos261d5ab2014-10-29 14:42:38 +0100871
Andres Morales23974272015-05-14 22:42:26 -0700872 @Override
873 public byte[] toHash(String password, int userId) {
874 return mLockPatternUtils.passwordToHash(password, userId);
875 }
Andres Morales59ef1262015-06-26 13:56:39 -0700876
877 @Override
878 public String adjustForKeystore(String password) {
879 return password;
880 }
Andres Morales23974272015-05-14 22:42:26 -0700881 }
882 );
883 }
884
885 private VerifyCredentialResponse verifyCredential(int userId, CredentialHash storedHash,
886 String credential, boolean hasChallenge, long challenge, CredentialUtil credentialUtil)
887 throws RemoteException {
888 if ((storedHash == null || storedHash.hash.length == 0) && TextUtils.isEmpty(credential)) {
889 // don't need to pass empty credentials to GateKeeper
890 return VerifyCredentialResponse.OK;
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700891 }
892
Andres Morales23974272015-05-14 22:42:26 -0700893 if (TextUtils.isEmpty(credential)) {
894 return VerifyCredentialResponse.ERROR;
Amith Yamasani52c489c2012-03-28 11:42:42 -0700895 }
Adrian Roos261d5ab2014-10-29 14:42:38 +0100896
Andres Morales8fa56652015-03-31 09:19:50 -0700897 if (storedHash.version == CredentialHash.VERSION_LEGACY) {
Andres Morales23974272015-05-14 22:42:26 -0700898 byte[] hash = credentialUtil.toHash(credential, userId);
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700899 if (Arrays.equals(hash, storedHash.hash)) {
Andres Morales59ef1262015-06-26 13:56:39 -0700900 unlockKeystore(credentialUtil.adjustForKeystore(credential), userId);
Jeff Sharkeyb9fe5372015-12-03 15:23:08 -0700901
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +0000902 // Users with legacy credentials don't have credential-backed
903 // FBE keys, so just pass through a fake token/secret
904 Slog.i(TAG, "Unlocking user with fake token: " + userId);
905 final byte[] fakeToken = String.valueOf(userId).getBytes();
906 unlockUser(userId, fakeToken, fakeToken);
Jeff Sharkeyb9fe5372015-12-03 15:23:08 -0700907
Andres Morales23974272015-05-14 22:42:26 -0700908 // migrate credential to GateKeeper
909 credentialUtil.setCredential(credential, null, userId);
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700910 if (!hasChallenge) {
Andres Morales23974272015-05-14 22:42:26 -0700911 return VerifyCredentialResponse.OK;
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700912 }
913 // Fall through to get the auth token. Technically this should never happen,
Andres Morales23974272015-05-14 22:42:26 -0700914 // as a user that had a legacy credential would have to unlock their device
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700915 // before getting to a flow with a challenge, but supporting for consistency.
916 } else {
Andres Morales23974272015-05-14 22:42:26 -0700917 return VerifyCredentialResponse.ERROR;
Andres Morales8fa56652015-03-31 09:19:50 -0700918 }
Andres Morales8fa56652015-03-31 09:19:50 -0700919 }
920
Andres Morales23974272015-05-14 22:42:26 -0700921 VerifyCredentialResponse response;
Paul Crowley98e0a262016-02-04 09:41:53 +0000922 boolean shouldReEnroll = false;
923 GateKeeperResponse gateKeeperResponse = getGateKeeperService()
924 .verifyChallenge(userId, challenge, storedHash.hash, credential.getBytes());
925 int responseCode = gateKeeperResponse.getResponseCode();
926 if (responseCode == GateKeeperResponse.RESPONSE_RETRY) {
927 response = new VerifyCredentialResponse(gateKeeperResponse.getTimeout());
928 } else if (responseCode == GateKeeperResponse.RESPONSE_OK) {
929 byte[] token = gateKeeperResponse.getPayload();
930 if (token == null) {
931 // something's wrong if there's no payload with a challenge
932 Slog.e(TAG, "verifyChallenge response had no associated payload");
Andres Morales23974272015-05-14 22:42:26 -0700933 response = VerifyCredentialResponse.ERROR;
Paul Crowley98e0a262016-02-04 09:41:53 +0000934 } else {
935 shouldReEnroll = gateKeeperResponse.getShouldReEnroll();
936 response = new VerifyCredentialResponse(token);
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700937 }
Andres Morales23974272015-05-14 22:42:26 -0700938 } else {
Paul Crowley98e0a262016-02-04 09:41:53 +0000939 response = VerifyCredentialResponse.ERROR;
Adrian Roos261d5ab2014-10-29 14:42:38 +0100940 }
Andres Morales8fa56652015-03-31 09:19:50 -0700941
Andres Morales23974272015-05-14 22:42:26 -0700942 if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
943 // credential has matched
944 unlockKeystore(credential, userId);
Jeff Sharkeyb9fe5372015-12-03 15:23:08 -0700945
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +0000946 Slog.i(TAG, "Unlocking user " + userId +
947 " with token length " + response.getPayload().length);
948 unlockUser(userId, response.getPayload(), secretFromCredential(credential));
Jeff Sharkeyb9fe5372015-12-03 15:23:08 -0700949
Clara Bayarri56878a92015-10-29 15:43:55 +0000950 UserInfo info = UserManager.get(mContext).getUserInfo(userId);
Clara Bayarria1771112015-12-18 16:29:18 +0000951 if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)) {
Clara Bayarri56878a92015-10-29 15:43:55 +0000952 TrustManager trustManager =
953 (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
954 trustManager.setDeviceLockedForUser(userId, false);
955 }
Andres Morales23974272015-05-14 22:42:26 -0700956 if (shouldReEnroll) {
957 credentialUtil.setCredential(credential, credential, userId);
958 }
Adrian Roos873010d2015-08-25 15:59:00 -0700959 } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
960 if (response.getTimeout() > 0) {
961 requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_LOCKOUT, userId);
962 }
Andres Morales23974272015-05-14 22:42:26 -0700963 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700964
Andres Morales23974272015-05-14 22:42:26 -0700965 return response;
966 }
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700967
Amith Yamasani52c489c2012-03-28 11:42:42 -0700968 @Override
Adrian Roos261d5ab2014-10-29 14:42:38 +0100969 public boolean checkVoldPassword(int userId) throws RemoteException {
Paul Lawrence945490c2014-03-27 16:37:28 +0000970 if (!mFirstCallToVold) {
971 return false;
972 }
973 mFirstCallToVold = false;
974
975 checkPasswordReadPermission(userId);
976
977 // There's no guarantee that this will safely connect, but if it fails
978 // we will simply show the lock screen when we shouldn't, so relatively
979 // benign. There is an outside chance something nasty would happen if
980 // this service restarted before vold stales out the password in this
981 // case. The nastiness is limited to not showing the lock screen when
982 // we should, within the first minute of decrypting the phone if this
983 // service can't connect to vold, it restarts, and then the new instance
984 // does successfully connect.
985 final IMountService service = getMountService();
986 String password = service.getPassword();
987 service.clearPassword();
988 if (password == null) {
989 return false;
990 }
991
992 try {
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100993 if (mLockPatternUtils.isLockPatternEnabled(userId)) {
Andres Morales23974272015-05-14 22:42:26 -0700994 if (checkPattern(password, userId).getResponseCode()
995 == GateKeeperResponse.RESPONSE_OK) {
Paul Lawrence945490c2014-03-27 16:37:28 +0000996 return true;
997 }
998 }
999 } catch (Exception e) {
1000 }
1001
1002 try {
Adrian Roos9dd16eb2015-01-08 16:20:49 +01001003 if (mLockPatternUtils.isLockPasswordEnabled(userId)) {
Andres Morales23974272015-05-14 22:42:26 -07001004 if (checkPassword(password, userId).getResponseCode()
1005 == GateKeeperResponse.RESPONSE_OK) {
Paul Lawrence945490c2014-03-27 16:37:28 +00001006 return true;
1007 }
1008 }
1009 } catch (Exception e) {
1010 }
1011
1012 return false;
1013 }
1014
Adrian Roosdb0f76e2015-01-07 22:19:38 +01001015 private void removeUser(int userId) {
Adrian Roos261d5ab2014-10-29 14:42:38 +01001016 mStorage.removeUser(userId);
Adrian Roosb5e47222015-08-14 15:53:06 -07001017 mStrongAuth.removeUser(userId);
Robin Lee49d810c2014-09-23 13:50:22 +01001018
1019 final KeyStore ks = KeyStore.getInstance();
Chad Brubaker83ce0952015-05-12 13:00:02 -07001020 ks.onUserRemoved(userId);
Andres Morales070fe632015-06-24 10:37:10 -07001021
1022 try {
1023 final IGateKeeperService gk = getGateKeeperService();
1024 if (gk != null) {
1025 gk.clearSecureUserId(userId);
1026 }
1027 } catch (RemoteException ex) {
1028 Slog.w(TAG, "unable to clear GK secure user id");
1029 }
Amith Yamasani52c489c2012-03-28 11:42:42 -07001030 }
1031
Adrian Roosb5e47222015-08-14 15:53:06 -07001032 @Override
1033 public void registerStrongAuthTracker(IStrongAuthTracker tracker) {
1034 checkPasswordReadPermission(UserHandle.USER_ALL);
1035 mStrongAuth.registerStrongAuthTracker(tracker);
1036 }
1037
1038 @Override
1039 public void unregisterStrongAuthTracker(IStrongAuthTracker tracker) {
1040 checkPasswordReadPermission(UserHandle.USER_ALL);
1041 mStrongAuth.unregisterStrongAuthTracker(tracker);
1042 }
1043
1044 @Override
1045 public void requireStrongAuth(int strongAuthReason, int userId) {
1046 checkWritePermission(userId);
1047 mStrongAuth.requireStrongAuth(strongAuthReason, userId);
1048 }
1049
Amith Yamasani52c489c2012-03-28 11:42:42 -07001050 private static final String[] VALID_SETTINGS = new String[] {
1051 LockPatternUtils.LOCKOUT_PERMANENT_KEY,
1052 LockPatternUtils.LOCKOUT_ATTEMPT_DEADLINE,
1053 LockPatternUtils.PATTERN_EVER_CHOSEN_KEY,
1054 LockPatternUtils.PASSWORD_TYPE_KEY,
1055 LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY,
1056 LockPatternUtils.LOCK_PASSWORD_SALT_KEY,
1057 LockPatternUtils.DISABLE_LOCKSCREEN_KEY,
1058 LockPatternUtils.LOCKSCREEN_OPTIONS,
1059 LockPatternUtils.LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK,
1060 LockPatternUtils.BIOMETRIC_WEAK_EVER_CHOSEN_KEY,
1061 LockPatternUtils.LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS,
1062 LockPatternUtils.PASSWORD_HISTORY_KEY,
1063 Secure.LOCK_PATTERN_ENABLED,
1064 Secure.LOCK_BIOMETRIC_WEAK_FLAGS,
1065 Secure.LOCK_PATTERN_VISIBLE,
1066 Secure.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED
Jim Miller187ec582013-04-15 18:27:54 -07001067 };
1068
Svetoslav Ganov6d2c0e52015-06-23 16:33:36 +00001069 // Reading these settings needs the contacts permission
1070 private static final String[] READ_CONTACTS_PROTECTED_SETTINGS = new String[] {
Jim Miller187ec582013-04-15 18:27:54 -07001071 Secure.LOCK_SCREEN_OWNER_INFO_ENABLED,
1072 Secure.LOCK_SCREEN_OWNER_INFO
1073 };
Paul Lawrence945490c2014-03-27 16:37:28 +00001074
Adrian Roos001b00d2015-02-24 17:08:48 +01001075 // Reading these settings needs the same permission as checking the password
1076 private static final String[] READ_PASSWORD_PROTECTED_SETTINGS = new String[] {
1077 LockPatternUtils.LOCK_PASSWORD_SALT_KEY,
1078 LockPatternUtils.PASSWORD_HISTORY_KEY,
Adrian Roos855fa302015-04-02 16:01:12 +02001079 LockPatternUtils.PASSWORD_TYPE_KEY,
Adrian Roos001b00d2015-02-24 17:08:48 +01001080 };
1081
Amith Yamasani072543f2015-02-13 11:09:45 -08001082 private static final String[] SETTINGS_TO_BACKUP = new String[] {
1083 Secure.LOCK_SCREEN_OWNER_INFO_ENABLED,
1084 Secure.LOCK_SCREEN_OWNER_INFO
1085 };
1086
Paul Lawrence945490c2014-03-27 16:37:28 +00001087 private IMountService getMountService() {
1088 final IBinder service = ServiceManager.getService("mount");
1089 if (service != null) {
1090 return IMountService.Stub.asInterface(service);
1091 }
1092 return null;
1093 }
Andres Morales8fa56652015-03-31 09:19:50 -07001094
Andres Morales301ea442015-04-17 09:15:47 -07001095 private class GateKeeperDiedRecipient implements IBinder.DeathRecipient {
1096 @Override
1097 public void binderDied() {
1098 mGateKeeperService.asBinder().unlinkToDeath(this, 0);
1099 mGateKeeperService = null;
1100 }
1101 }
1102
1103 private synchronized IGateKeeperService getGateKeeperService()
1104 throws RemoteException {
Andres Morales8fa56652015-03-31 09:19:50 -07001105 if (mGateKeeperService != null) {
1106 return mGateKeeperService;
1107 }
1108
1109 final IBinder service =
1110 ServiceManager.getService("android.service.gatekeeper.IGateKeeperService");
1111 if (service != null) {
Andres Morales301ea442015-04-17 09:15:47 -07001112 service.linkToDeath(new GateKeeperDiedRecipient(), 0);
Andres Morales8fa56652015-03-31 09:19:50 -07001113 mGateKeeperService = IGateKeeperService.Stub.asInterface(service);
1114 return mGateKeeperService;
1115 }
1116
1117 Slog.e(TAG, "Unable to acquire GateKeeperService");
1118 return null;
1119 }
Amith Yamasani52c489c2012-03-28 11:42:42 -07001120}