blob: ee73b1a6ea846d6464b2baf9b959d464c7be1014 [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
Adrian Roos230635e2015-01-07 20:50:29 +010019import android.app.admin.DevicePolicyManager;
Amith Yamasani072543f2015-02-13 11:09:45 -080020import android.app.backup.BackupManager;
Robin Leef0246a82014-08-13 09:50:25 +010021import android.content.BroadcastReceiver;
Amith Yamasani52c489c2012-03-28 11:42:42 -070022import android.content.ContentResolver;
Amith Yamasani52c489c2012-03-28 11:42:42 -070023import android.content.Context;
Robin Leef0246a82014-08-13 09:50:25 +010024import android.content.Intent;
25import android.content.IntentFilter;
Jim Miller158fe192013-04-17 15:23:55 -070026import android.content.pm.PackageManager;
Jim Miller187ec582013-04-15 18:27:54 -070027import android.content.pm.UserInfo;
28
Adrian Roos261d5ab2014-10-29 14:42:38 +010029import static android.Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE;
Jim Miller187ec582013-04-15 18:27:54 -070030import static android.content.Context.USER_SERVICE;
Jim Miller158fe192013-04-17 15:23:55 -070031import static android.Manifest.permission.READ_PROFILE;
Adrian Roos261d5ab2014-10-29 14:42:38 +010032
Amith Yamasani52c489c2012-03-28 11:42:42 -070033import android.database.sqlite.SQLiteDatabase;
Amith Yamasani52c489c2012-03-28 11:42:42 -070034import android.os.Binder;
Paul Lawrence945490c2014-03-27 16:37:28 +000035import android.os.IBinder;
Robin Leef0246a82014-08-13 09:50:25 +010036import android.os.Process;
Amith Yamasani52c489c2012-03-28 11:42:42 -070037import android.os.RemoteException;
Paul Lawrence945490c2014-03-27 16:37:28 +000038import android.os.storage.IMountService;
39import android.os.ServiceManager;
Amith Yamasanid1645f82012-06-12 11:53:26 -070040import android.os.SystemProperties;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070041import android.os.UserHandle;
Jim Miller187ec582013-04-15 18:27:54 -070042import android.os.UserManager;
Amith Yamasani52c489c2012-03-28 11:42:42 -070043import android.provider.Settings;
44import android.provider.Settings.Secure;
Jim Miller187ec582013-04-15 18:27:54 -070045import android.provider.Settings.SettingNotFoundException;
Jim Millerde1af082013-09-11 14:58:26 -070046import android.security.KeyStore;
Andres Morales8fa56652015-03-31 09:19:50 -070047import android.service.gatekeeper.IGateKeeperService;
Amith Yamasani52c489c2012-03-28 11:42:42 -070048import android.text.TextUtils;
49import android.util.Slog;
50
Amith Yamasani072543f2015-02-13 11:09:45 -080051import com.android.internal.util.ArrayUtils;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080052import com.android.internal.widget.ILockSettings;
53import com.android.internal.widget.LockPatternUtils;
Andres Morales8fa56652015-03-31 09:19:50 -070054import com.android.server.LockSettingsStorage.CredentialHash;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080055
Amith Yamasani52c489c2012-03-28 11:42:42 -070056import java.util.Arrays;
Jim Miller187ec582013-04-15 18:27:54 -070057import java.util.List;
Amith Yamasani52c489c2012-03-28 11:42:42 -070058
59/**
60 * Keeps the lock pattern/password data and related settings for each user.
61 * Used by LockPatternUtils. Needs to be a service because Settings app also needs
62 * to be able to save lockscreen information for secondary users.
63 * @hide
64 */
65public class LockSettingsService extends ILockSettings.Stub {
66
Adrian Roos261d5ab2014-10-29 14:42:38 +010067 private static final String PERMISSION = ACCESS_KEYGUARD_SECURE_STORAGE;
Adrian Roos4f788452014-05-22 20:45:59 +020068
Amith Yamasani52c489c2012-03-28 11:42:42 -070069 private static final String TAG = "LockSettingsService";
70
Amith Yamasani52c489c2012-03-28 11:42:42 -070071 private final Context mContext;
Adrian Roos261d5ab2014-10-29 14:42:38 +010072
73 private final LockSettingsStorage mStorage;
74
Jim Millerde1af082013-09-11 14:58:26 -070075 private LockPatternUtils mLockPatternUtils;
Paul Lawrence945490c2014-03-27 16:37:28 +000076 private boolean mFirstCallToVold;
Andres Morales8fa56652015-03-31 09:19:50 -070077 private IGateKeeperService mGateKeeperService;
Amith Yamasani52c489c2012-03-28 11:42:42 -070078
79 public LockSettingsService(Context context) {
80 mContext = context;
81 // Open the database
Jim Millerde1af082013-09-11 14:58:26 -070082
83 mLockPatternUtils = new LockPatternUtils(context);
Paul Lawrence945490c2014-03-27 16:37:28 +000084 mFirstCallToVold = true;
Robin Leef0246a82014-08-13 09:50:25 +010085
86 IntentFilter filter = new IntentFilter();
87 filter.addAction(Intent.ACTION_USER_ADDED);
Adrian Roos3dcae682014-10-29 14:43:56 +010088 filter.addAction(Intent.ACTION_USER_STARTING);
Adrian Roosdb0f76e2015-01-07 22:19:38 +010089 filter.addAction(Intent.ACTION_USER_REMOVED);
Robin Leef0246a82014-08-13 09:50:25 +010090 mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
Adrian Roos261d5ab2014-10-29 14:42:38 +010091
92 mStorage = new LockSettingsStorage(context, new LockSettingsStorage.Callback() {
93 @Override
94 public void initialize(SQLiteDatabase db) {
95 // Get the lockscreen default from a system property, if available
96 boolean lockScreenDisable = SystemProperties.getBoolean(
97 "ro.lockscreen.disable.default", false);
98 if (lockScreenDisable) {
99 mStorage.writeKeyValue(db, LockPatternUtils.DISABLE_LOCKSCREEN_KEY, "1", 0);
100 }
101 }
102 });
Amith Yamasani52c489c2012-03-28 11:42:42 -0700103 }
104
Robin Leef0246a82014-08-13 09:50:25 +0100105 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
106 @Override
107 public void onReceive(Context context, Intent intent) {
Robin Lee1096cf82014-09-01 16:52:47 +0100108 if (Intent.ACTION_USER_ADDED.equals(intent.getAction())) {
Robin Leef0246a82014-08-13 09:50:25 +0100109 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
Robin Lee49d810c2014-09-23 13:50:22 +0100110 final int userSysUid = UserHandle.getUid(userHandle, Process.SYSTEM_UID);
111 final KeyStore ks = KeyStore.getInstance();
112
113 // Clear up keystore in case anything was left behind by previous users
114 ks.resetUid(userSysUid);
115
116 // If this user has a parent, sync with its keystore password
Robin Leef0246a82014-08-13 09:50:25 +0100117 final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
118 final UserInfo parentInfo = um.getProfileParent(userHandle);
119 if (parentInfo != null) {
Robin Lee49d810c2014-09-23 13:50:22 +0100120 final int parentSysUid = UserHandle.getUid(parentInfo.id, Process.SYSTEM_UID);
121 ks.syncUid(parentSysUid, userSysUid);
Robin Leef0246a82014-08-13 09:50:25 +0100122 }
Adrian Roos3dcae682014-10-29 14:43:56 +0100123 } else if (Intent.ACTION_USER_STARTING.equals(intent.getAction())) {
124 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
125 mStorage.prefetchUser(userHandle);
Adrian Roosdb0f76e2015-01-07 22:19:38 +0100126 } else if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
127 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
128 if (userHandle > 0) {
129 removeUser(userHandle);
130 }
Robin Leef0246a82014-08-13 09:50:25 +0100131 }
132 }
133 };
134
Amith Yamasani52c489c2012-03-28 11:42:42 -0700135 public void systemReady() {
136 migrateOldData();
Andres Morales8fa56652015-03-31 09:19:50 -0700137 getGateKeeperService();
Adrian Roos3dcae682014-10-29 14:43:56 +0100138 mStorage.prefetchUser(UserHandle.USER_OWNER);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700139 }
140
141 private void migrateOldData() {
142 try {
Jim Miller187ec582013-04-15 18:27:54 -0700143 // These Settings moved before multi-user was enabled, so we only have to do it for the
144 // root user.
145 if (getString("migrated", null, 0) == null) {
146 final ContentResolver cr = mContext.getContentResolver();
147 for (String validSetting : VALID_SETTINGS) {
148 String value = Settings.Secure.getString(cr, validSetting);
149 if (value != null) {
150 setString(validSetting, value, 0);
151 }
152 }
153 // No need to move the password / pattern files. They're already in the right place.
154 setString("migrated", "true", 0);
155 Slog.i(TAG, "Migrated lock settings to new location");
Amith Yamasani52c489c2012-03-28 11:42:42 -0700156 }
157
Jim Miller187ec582013-04-15 18:27:54 -0700158 // These Settings changed after multi-user was enabled, hence need to be moved per user.
159 if (getString("migrated_user_specific", null, 0) == null) {
160 final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
161 final ContentResolver cr = mContext.getContentResolver();
162 List<UserInfo> users = um.getUsers();
163 for (int user = 0; user < users.size(); user++) {
Jim Miller2d8ecf9d2013-04-22 17:17:03 -0700164 // Migrate owner info
165 final int userId = users.get(user).id;
166 final String OWNER_INFO = Secure.LOCK_SCREEN_OWNER_INFO;
167 String ownerInfo = Settings.Secure.getStringForUser(cr, OWNER_INFO, userId);
168 if (ownerInfo != null) {
169 setString(OWNER_INFO, ownerInfo, userId);
170 Settings.Secure.putStringForUser(cr, ownerInfo, "", userId);
171 }
Jim Miller187ec582013-04-15 18:27:54 -0700172
Jim Miller2d8ecf9d2013-04-22 17:17:03 -0700173 // Migrate owner info enabled. Note there was a bug where older platforms only
174 // stored this value if the checkbox was toggled at least once. The code detects
175 // this case by handling the exception.
176 final String OWNER_INFO_ENABLED = Secure.LOCK_SCREEN_OWNER_INFO_ENABLED;
177 boolean enabled;
178 try {
179 int ivalue = Settings.Secure.getIntForUser(cr, OWNER_INFO_ENABLED, userId);
180 enabled = ivalue != 0;
181 setLong(OWNER_INFO_ENABLED, enabled ? 1 : 0, userId);
182 } catch (SettingNotFoundException e) {
183 // Setting was never stored. Store it if the string is not empty.
184 if (!TextUtils.isEmpty(ownerInfo)) {
185 setLong(OWNER_INFO_ENABLED, 1, userId);
Jim Miller187ec582013-04-15 18:27:54 -0700186 }
187 }
Jim Miller2d8ecf9d2013-04-22 17:17:03 -0700188 Settings.Secure.putIntForUser(cr, OWNER_INFO_ENABLED, 0, userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700189 }
Jim Miller187ec582013-04-15 18:27:54 -0700190 // No need to move the password / pattern files. They're already in the right place.
191 setString("migrated_user_specific", "true", 0);
192 Slog.i(TAG, "Migrated per-user lock settings to new location");
Amith Yamasani52c489c2012-03-28 11:42:42 -0700193 }
Adrian Roos230635e2015-01-07 20:50:29 +0100194
195 // Migrates biometric weak such that the fallback mechanism becomes the primary.
196 if (getString("migrated_biometric_weak", null, 0) == null) {
197 final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
198 List<UserInfo> users = um.getUsers();
199 for (int i = 0; i < users.size(); i++) {
200 int userId = users.get(i).id;
201 long type = getLong(LockPatternUtils.PASSWORD_TYPE_KEY,
202 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
203 userId);
204 long alternateType = getLong(LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY,
205 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
206 userId);
207 if (type == DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK) {
208 setLong(LockPatternUtils.PASSWORD_TYPE_KEY,
209 alternateType,
210 userId);
211 }
212 setLong(LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY,
213 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
214 userId);
215 }
216 setString("migrated_biometric_weak", "true", 0);
217 Slog.i(TAG, "Migrated biometric weak to use the fallback instead");
218 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700219 } catch (RemoteException re) {
Jim Miller187ec582013-04-15 18:27:54 -0700220 Slog.e(TAG, "Unable to migrate old data", re);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700221 }
222 }
223
Jim Miller5ecd8112013-01-09 18:50:26 -0800224 private final void checkWritePermission(int userId) {
Jim Miller505329b2013-11-08 13:25:36 -0800225 mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsWrite");
Amith Yamasani52c489c2012-03-28 11:42:42 -0700226 }
227
Jim Miller5ecd8112013-01-09 18:50:26 -0800228 private final void checkPasswordReadPermission(int userId) {
Jim Miller505329b2013-11-08 13:25:36 -0800229 mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsRead");
Amith Yamasani52c489c2012-03-28 11:42:42 -0700230 }
231
Jim Miller158fe192013-04-17 15:23:55 -0700232 private final void checkReadPermission(String requestedKey, int userId) {
Amith Yamasani52c489c2012-03-28 11:42:42 -0700233 final int callingUid = Binder.getCallingUid();
Adrian Roos001b00d2015-02-24 17:08:48 +0100234
Jim Miller158fe192013-04-17 15:23:55 -0700235 for (int i = 0; i < READ_PROFILE_PROTECTED_SETTINGS.length; i++) {
236 String key = READ_PROFILE_PROTECTED_SETTINGS[i];
237 if (key.equals(requestedKey) && mContext.checkCallingOrSelfPermission(READ_PROFILE)
238 != PackageManager.PERMISSION_GRANTED) {
239 throw new SecurityException("uid=" + callingUid
240 + " needs permission " + READ_PROFILE + " to read "
241 + requestedKey + " for user " + userId);
242 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700243 }
Adrian Roos001b00d2015-02-24 17:08:48 +0100244
245 for (int i = 0; i < READ_PASSWORD_PROTECTED_SETTINGS.length; i++) {
246 String key = READ_PASSWORD_PROTECTED_SETTINGS[i];
247 if (key.equals(requestedKey) && mContext.checkCallingOrSelfPermission(PERMISSION)
248 != PackageManager.PERMISSION_GRANTED) {
249 throw new SecurityException("uid=" + callingUid
250 + " needs permission " + PERMISSION + " to read "
251 + requestedKey + " for user " + userId);
252 }
253 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700254 }
255
256 @Override
257 public void setBoolean(String key, boolean value, int userId) throws RemoteException {
258 checkWritePermission(userId);
Adrian Roos261d5ab2014-10-29 14:42:38 +0100259 setStringUnchecked(key, userId, value ? "1" : "0");
Amith Yamasani52c489c2012-03-28 11:42:42 -0700260 }
261
262 @Override
263 public void setLong(String key, long value, int userId) throws RemoteException {
264 checkWritePermission(userId);
Adrian Roos261d5ab2014-10-29 14:42:38 +0100265 setStringUnchecked(key, userId, Long.toString(value));
Amith Yamasani52c489c2012-03-28 11:42:42 -0700266 }
267
268 @Override
269 public void setString(String key, String value, int userId) throws RemoteException {
270 checkWritePermission(userId);
Adrian Roos261d5ab2014-10-29 14:42:38 +0100271 setStringUnchecked(key, userId, value);
272 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700273
Adrian Roos261d5ab2014-10-29 14:42:38 +0100274 private void setStringUnchecked(String key, int userId, String value) {
275 mStorage.writeKeyValue(key, value, userId);
Amith Yamasani072543f2015-02-13 11:09:45 -0800276 if (ArrayUtils.contains(SETTINGS_TO_BACKUP, key)) {
277 BackupManager.dataChanged("com.android.providers.settings");
278 }
Amith Yamasani52c489c2012-03-28 11:42:42 -0700279 }
280
281 @Override
282 public boolean getBoolean(String key, boolean defaultValue, int userId) throws RemoteException {
Jim Miller158fe192013-04-17 15:23:55 -0700283 checkReadPermission(key, userId);
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100284 String value = getStringUnchecked(key, null, userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700285 return TextUtils.isEmpty(value) ?
286 defaultValue : (value.equals("1") || value.equals("true"));
287 }
288
289 @Override
290 public long getLong(String key, long defaultValue, int userId) throws RemoteException {
Jim Miller158fe192013-04-17 15:23:55 -0700291 checkReadPermission(key, userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700292
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100293 String value = getStringUnchecked(key, null, userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700294 return TextUtils.isEmpty(value) ? defaultValue : Long.parseLong(value);
295 }
296
297 @Override
298 public String getString(String key, String defaultValue, int userId) throws RemoteException {
Jim Miller158fe192013-04-17 15:23:55 -0700299 checkReadPermission(key, userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700300
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100301 return getStringUnchecked(key, defaultValue, userId);
302 }
303
304 public String getStringUnchecked(String key, String defaultValue, int userId) {
305 if (Settings.Secure.LOCK_PATTERN_ENABLED.equals(key)) {
306 return mLockPatternUtils.isLockPatternEnabled(userId) ? "1" : "0";
307 }
308
Adrian Roos261d5ab2014-10-29 14:42:38 +0100309 return mStorage.readKeyValue(key, defaultValue, userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700310 }
311
Adrian Roos4f788452014-05-22 20:45:59 +0200312 @Override
Amith Yamasani52c489c2012-03-28 11:42:42 -0700313 public boolean havePassword(int userId) throws RemoteException {
314 // Do we need a permissions check here?
315
Adrian Roos261d5ab2014-10-29 14:42:38 +0100316 return mStorage.hasPassword(userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700317 }
318
319 @Override
320 public boolean havePattern(int userId) throws RemoteException {
321 // Do we need a permissions check here?
322
Adrian Roos261d5ab2014-10-29 14:42:38 +0100323 return mStorage.hasPattern(userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700324 }
325
Robin Leef0246a82014-08-13 09:50:25 +0100326 private void maybeUpdateKeystore(String password, int userHandle) {
327 final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
328 final KeyStore ks = KeyStore.getInstance();
329
330 final List<UserInfo> profiles = um.getProfiles(userHandle);
331 boolean shouldReset = TextUtils.isEmpty(password);
332
333 // For historical reasons, don't wipe a non-empty keystore if we have a single user with a
334 // single profile.
335 if (userHandle == UserHandle.USER_OWNER && profiles.size() == 1) {
336 if (!ks.isEmpty()) {
337 shouldReset = false;
338 }
339 }
340
341 for (UserInfo pi : profiles) {
342 final int profileUid = UserHandle.getUid(pi.id, Process.SYSTEM_UID);
343 if (shouldReset) {
344 ks.resetUid(profileUid);
Jim Millerde1af082013-09-11 14:58:26 -0700345 } else {
Robin Leef0246a82014-08-13 09:50:25 +0100346 ks.passwordUid(password, profileUid);
Jim Millerde1af082013-09-11 14:58:26 -0700347 }
348 }
349 }
350
Amith Yamasani52c489c2012-03-28 11:42:42 -0700351
Andres Morales8fa56652015-03-31 09:19:50 -0700352 private byte[] getCurrentHandle(int userId) {
353 CredentialHash credential;
354 byte[] currentHandle;
Jim Millerde1af082013-09-11 14:58:26 -0700355
Andres Morales8fa56652015-03-31 09:19:50 -0700356 int currentHandleType = mStorage.getStoredCredentialType(userId);
357 switch (currentHandleType) {
358 case CredentialHash.TYPE_PATTERN:
359 credential = mStorage.readPatternHash(userId);
360 currentHandle = credential != null
361 ? credential.hash
362 : null;
363 break;
364 case CredentialHash.TYPE_PASSWORD:
365 credential = mStorage.readPasswordHash(userId);
366 currentHandle = credential != null
367 ? credential.hash
368 : null;
369 break;
370 case CredentialHash.TYPE_NONE:
371 default:
372 currentHandle = null;
373 break;
374 }
375
376 // sanity check
377 if (currentHandleType != CredentialHash.TYPE_NONE && currentHandle == null) {
378 Slog.e(TAG, "Stored handle type [" + currentHandleType + "] but no handle available");
379 }
380
381 return currentHandle;
Amith Yamasani52c489c2012-03-28 11:42:42 -0700382 }
383
Andres Morales8fa56652015-03-31 09:19:50 -0700384
Amith Yamasani52c489c2012-03-28 11:42:42 -0700385 @Override
Andres Morales8fa56652015-03-31 09:19:50 -0700386 public void setLockPattern(String pattern, String savedCredential, int userId)
387 throws RemoteException {
388 byte[] currentHandle = getCurrentHandle(userId);
389
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700390 if (pattern == null) {
391 mStorage.writePatternHash(null, userId);
392 return;
393 }
394
Andres Morales8fa56652015-03-31 09:19:50 -0700395 if (currentHandle == null) {
396 if (savedCredential != null) {
397 Slog.w(TAG, "Saved credential provided, but none stored");
398 }
399 savedCredential = null;
400 }
401
402 byte[] enrolledHandle = enrollCredential(currentHandle, savedCredential, pattern, userId);
403 if (enrolledHandle != null) {
404 mStorage.writePatternHash(enrolledHandle, userId);
405 } else {
406 Slog.e(TAG, "Failed to enroll pattern");
407 }
408 }
409
410
411 @Override
412 public void setLockPassword(String password, String savedCredential, int userId)
413 throws RemoteException {
Andres Morales8fa56652015-03-31 09:19:50 -0700414 byte[] currentHandle = getCurrentHandle(userId);
415
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700416 if (password == null) {
417 mStorage.writePasswordHash(null, userId);
418 return;
419 }
420
Andres Morales8fa56652015-03-31 09:19:50 -0700421 if (currentHandle == null) {
422 if (savedCredential != null) {
423 Slog.w(TAG, "Saved credential provided, but none stored");
424 }
425 savedCredential = null;
426 }
427
428 byte[] enrolledHandle = enrollCredential(currentHandle, savedCredential, password, userId);
429 if (enrolledHandle != null) {
430 mStorage.writePasswordHash(enrolledHandle, userId);
431 } else {
432 Slog.e(TAG, "Failed to enroll password");
433 }
434 }
435
436 private byte[] enrollCredential(byte[] enrolledHandle,
437 String enrolledCredential, String toEnroll, int userId)
438 throws RemoteException {
Jim Millerde1af082013-09-11 14:58:26 -0700439 checkWritePermission(userId);
Andres Morales8fa56652015-03-31 09:19:50 -0700440 byte[] enrolledCredentialBytes = enrolledCredential == null
441 ? null
442 : enrolledCredential.getBytes();
443 byte[] toEnrollBytes = toEnroll == null
444 ? null
445 : toEnroll.getBytes();
446 byte[] hash = getGateKeeperService().enroll(userId, enrolledHandle, enrolledCredentialBytes,
447 toEnrollBytes);
Jim Millerde1af082013-09-11 14:58:26 -0700448
Andres Morales8fa56652015-03-31 09:19:50 -0700449 if (hash != null) {
450 maybeUpdateKeystore(toEnroll, userId);
451 }
Jim Millerde1af082013-09-11 14:58:26 -0700452
Andres Morales8fa56652015-03-31 09:19:50 -0700453 return hash;
Jim Millerde1af082013-09-11 14:58:26 -0700454 }
455
456 @Override
457 public boolean checkPattern(String pattern, int userId) throws RemoteException {
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700458 try {
459 doVerifyPattern(pattern, false, 0, userId);
460 } catch (VerificationFailedException ex) {
461 return false;
462 }
Andres Morales8fa56652015-03-31 09:19:50 -0700463
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700464 return true;
465 }
Adrian Roos261d5ab2014-10-29 14:42:38 +0100466
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700467 @Override
468 public byte[] verifyPattern(String pattern, long challenge, int userId)
469 throws RemoteException {
470 try {
471 return doVerifyPattern(pattern, true, challenge, userId);
472 } catch (VerificationFailedException ex) {
473 return null;
474 }
475 }
476
477 private byte[] doVerifyPattern(String pattern, boolean hasChallenge, long challenge,
478 int userId) throws VerificationFailedException, RemoteException {
479 checkPasswordReadPermission(userId);
480
481 CredentialHash storedHash = mStorage.readPatternHash(userId);
482
483 if ((storedHash == null || storedHash.hash.length == 0) && TextUtils.isEmpty(pattern)) {
484 // don't need to pass empty passwords to GateKeeper
485 return null;
486 }
487
488 if (TextUtils.isEmpty(pattern)) {
489 throw new VerificationFailedException();
Amith Yamasani52c489c2012-03-28 11:42:42 -0700490 }
Adrian Roos261d5ab2014-10-29 14:42:38 +0100491
Andres Morales8fa56652015-03-31 09:19:50 -0700492 if (storedHash.version == CredentialHash.VERSION_LEGACY) {
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700493 byte[] hash = mLockPatternUtils.patternToHash(
494 mLockPatternUtils.stringToPattern(pattern));
495 if (Arrays.equals(hash, storedHash.hash)) {
Andres Morales8fa56652015-03-31 09:19:50 -0700496 maybeUpdateKeystore(pattern, userId);
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700497 // migrate password to GateKeeper
Andres Morales8fa56652015-03-31 09:19:50 -0700498 setLockPattern(pattern, null, userId);
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700499 if (!hasChallenge) {
500 return null;
501 }
502 // Fall through to get the auth token. Technically this should never happen,
503 // as a user that had a legacy pattern would have to unlock their device
504 // before getting to a flow with a challenge, but supporting for consistency.
505 } else {
506 throw new VerificationFailedException();
Andres Morales8fa56652015-03-31 09:19:50 -0700507 }
Andres Morales8fa56652015-03-31 09:19:50 -0700508 }
509
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700510 byte[] token = null;
511 if (hasChallenge) {
512 token = getGateKeeperService()
513 .verifyChallenge(userId, challenge, storedHash.hash, pattern.getBytes());
514 if (token == null) {
515 throw new VerificationFailedException();
516 }
517 } else if (!getGateKeeperService().verify(userId, storedHash.hash, pattern.getBytes())) {
518 throw new VerificationFailedException();
Adrian Roos261d5ab2014-10-29 14:42:38 +0100519 }
Andres Morales8fa56652015-03-31 09:19:50 -0700520
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700521 // pattern has matched
522 maybeUpdateKeystore(pattern, userId);
523 return token;
524
Amith Yamasani52c489c2012-03-28 11:42:42 -0700525 }
526
527 @Override
Jim Millerde1af082013-09-11 14:58:26 -0700528 public boolean checkPassword(String password, int userId) throws RemoteException {
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700529 try {
530 doVerifyPassword(password, false, 0, userId);
531 } catch (VerificationFailedException ex) {
532 return false;
533 }
534 return true;
535 }
536
537 @Override
538 public byte[] verifyPassword(String password, long challenge, int userId)
539 throws RemoteException {
540 try {
541 return doVerifyPassword(password, true, challenge, userId);
542 } catch (VerificationFailedException ex) {
543 return null;
544 }
545 }
546
547 private byte[] doVerifyPassword(String password, boolean hasChallenge, long challenge,
548 int userId) throws VerificationFailedException, RemoteException {
549 checkPasswordReadPermission(userId);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700550
Andres Morales8fa56652015-03-31 09:19:50 -0700551 CredentialHash storedHash = mStorage.readPasswordHash(userId);
Adrian Roos261d5ab2014-10-29 14:42:38 +0100552
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700553 if ((storedHash == null || storedHash.hash.length == 0) && TextUtils.isEmpty(password)) {
554 // don't need to pass empty passwords to GateKeeper
555 return null;
556 }
557
558 if (TextUtils.isEmpty(password)) {
559 throw new VerificationFailedException();
Amith Yamasani52c489c2012-03-28 11:42:42 -0700560 }
Adrian Roos261d5ab2014-10-29 14:42:38 +0100561
Andres Morales8fa56652015-03-31 09:19:50 -0700562 if (storedHash.version == CredentialHash.VERSION_LEGACY) {
563 byte[] hash = mLockPatternUtils.passwordToHash(password, userId);
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700564 if (Arrays.equals(hash, storedHash.hash)) {
Andres Morales8fa56652015-03-31 09:19:50 -0700565 maybeUpdateKeystore(password, userId);
566 // migrate password to GateKeeper
567 setLockPassword(password, null, userId);
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700568 if (!hasChallenge) {
569 return null;
570 }
571 // Fall through to get the auth token. Technically this should never happen,
572 // as a user that had a legacy password would have to unlock their device
573 // before getting to a flow with a challenge, but supporting for consistency.
574 } else {
575 throw new VerificationFailedException();
Andres Morales8fa56652015-03-31 09:19:50 -0700576 }
Andres Morales8fa56652015-03-31 09:19:50 -0700577 }
578
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700579 byte[] token = null;
580 if (hasChallenge) {
581 token = getGateKeeperService()
582 .verifyChallenge(userId, challenge, storedHash.hash, password.getBytes());
583 if (token == null) {
584 throw new VerificationFailedException();
585 }
586 } else if (!getGateKeeperService().verify(userId, storedHash.hash, password.getBytes())) {
587 throw new VerificationFailedException();
Adrian Roos261d5ab2014-10-29 14:42:38 +0100588 }
Andres Morales8fa56652015-03-31 09:19:50 -0700589
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700590 // password has matched
591 maybeUpdateKeystore(password, userId);
592 return token;
Amith Yamasani52c489c2012-03-28 11:42:42 -0700593 }
594
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700595
Amith Yamasani52c489c2012-03-28 11:42:42 -0700596 @Override
Adrian Roos261d5ab2014-10-29 14:42:38 +0100597 public boolean checkVoldPassword(int userId) throws RemoteException {
Paul Lawrence945490c2014-03-27 16:37:28 +0000598 if (!mFirstCallToVold) {
599 return false;
600 }
601 mFirstCallToVold = false;
602
603 checkPasswordReadPermission(userId);
604
605 // There's no guarantee that this will safely connect, but if it fails
606 // we will simply show the lock screen when we shouldn't, so relatively
607 // benign. There is an outside chance something nasty would happen if
608 // this service restarted before vold stales out the password in this
609 // case. The nastiness is limited to not showing the lock screen when
610 // we should, within the first minute of decrypting the phone if this
611 // service can't connect to vold, it restarts, and then the new instance
612 // does successfully connect.
613 final IMountService service = getMountService();
614 String password = service.getPassword();
615 service.clearPassword();
616 if (password == null) {
617 return false;
618 }
619
620 try {
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100621 if (mLockPatternUtils.isLockPatternEnabled(userId)) {
Paul Lawrence945490c2014-03-27 16:37:28 +0000622 if (checkPattern(password, userId)) {
623 return true;
624 }
625 }
626 } catch (Exception e) {
627 }
628
629 try {
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100630 if (mLockPatternUtils.isLockPasswordEnabled(userId)) {
Paul Lawrence945490c2014-03-27 16:37:28 +0000631 if (checkPassword(password, userId)) {
632 return true;
633 }
634 }
635 } catch (Exception e) {
636 }
637
638 return false;
639 }
640
Adrian Roosdb0f76e2015-01-07 22:19:38 +0100641 private void removeUser(int userId) {
Adrian Roos261d5ab2014-10-29 14:42:38 +0100642 mStorage.removeUser(userId);
Robin Lee49d810c2014-09-23 13:50:22 +0100643
644 final KeyStore ks = KeyStore.getInstance();
645 final int userUid = UserHandle.getUid(userId, Process.SYSTEM_UID);
646 ks.resetUid(userUid);
Amith Yamasani52c489c2012-03-28 11:42:42 -0700647 }
648
Amith Yamasani52c489c2012-03-28 11:42:42 -0700649 private static final String[] VALID_SETTINGS = new String[] {
650 LockPatternUtils.LOCKOUT_PERMANENT_KEY,
651 LockPatternUtils.LOCKOUT_ATTEMPT_DEADLINE,
652 LockPatternUtils.PATTERN_EVER_CHOSEN_KEY,
653 LockPatternUtils.PASSWORD_TYPE_KEY,
654 LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY,
655 LockPatternUtils.LOCK_PASSWORD_SALT_KEY,
656 LockPatternUtils.DISABLE_LOCKSCREEN_KEY,
657 LockPatternUtils.LOCKSCREEN_OPTIONS,
658 LockPatternUtils.LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK,
659 LockPatternUtils.BIOMETRIC_WEAK_EVER_CHOSEN_KEY,
660 LockPatternUtils.LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS,
661 LockPatternUtils.PASSWORD_HISTORY_KEY,
662 Secure.LOCK_PATTERN_ENABLED,
663 Secure.LOCK_BIOMETRIC_WEAK_FLAGS,
664 Secure.LOCK_PATTERN_VISIBLE,
665 Secure.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED
Jim Miller187ec582013-04-15 18:27:54 -0700666 };
667
Adrian Roos001b00d2015-02-24 17:08:48 +0100668 // Reading these settings needs the profile permission
Jim Miller2d8ecf9d2013-04-22 17:17:03 -0700669 private static final String[] READ_PROFILE_PROTECTED_SETTINGS = new String[] {
Jim Miller187ec582013-04-15 18:27:54 -0700670 Secure.LOCK_SCREEN_OWNER_INFO_ENABLED,
671 Secure.LOCK_SCREEN_OWNER_INFO
672 };
Paul Lawrence945490c2014-03-27 16:37:28 +0000673
Adrian Roos001b00d2015-02-24 17:08:48 +0100674 // Reading these settings needs the same permission as checking the password
675 private static final String[] READ_PASSWORD_PROTECTED_SETTINGS = new String[] {
676 LockPatternUtils.LOCK_PASSWORD_SALT_KEY,
677 LockPatternUtils.PASSWORD_HISTORY_KEY,
Adrian Roos855fa302015-04-02 16:01:12 +0200678 LockPatternUtils.PASSWORD_TYPE_KEY,
Adrian Roos001b00d2015-02-24 17:08:48 +0100679 };
680
Amith Yamasani072543f2015-02-13 11:09:45 -0800681 private static final String[] SETTINGS_TO_BACKUP = new String[] {
682 Secure.LOCK_SCREEN_OWNER_INFO_ENABLED,
683 Secure.LOCK_SCREEN_OWNER_INFO
684 };
685
Paul Lawrence945490c2014-03-27 16:37:28 +0000686 private IMountService getMountService() {
687 final IBinder service = ServiceManager.getService("mount");
688 if (service != null) {
689 return IMountService.Stub.asInterface(service);
690 }
691 return null;
692 }
Andres Morales8fa56652015-03-31 09:19:50 -0700693
694 private synchronized IGateKeeperService getGateKeeperService() {
695 if (mGateKeeperService != null) {
696 return mGateKeeperService;
697 }
698
699 final IBinder service =
700 ServiceManager.getService("android.service.gatekeeper.IGateKeeperService");
701 if (service != null) {
702 mGateKeeperService = IGateKeeperService.Stub.asInterface(service);
703 return mGateKeeperService;
704 }
705
706 Slog.e(TAG, "Unable to acquire GateKeeperService");
707 return null;
708 }
709
Andres Moralesd9fc85a2015-04-09 19:14:42 -0700710 private class VerificationFailedException extends Exception {}
711
Amith Yamasani52c489c2012-03-28 11:42:42 -0700712}