1 /* 2 * Copyright (C) 2019 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.car.settings.setupservice; 18 19 import android.app.Service; 20 import android.app.admin.DevicePolicyManager; 21 import android.content.Intent; 22 import android.content.pm.PackageManager; 23 import android.os.IBinder; 24 import android.os.UserHandle; 25 26 import com.android.car.settings.R; 27 import com.android.car.settings.common.Logger; 28 import com.android.car.settings.security.PasswordHelper; 29 import com.android.car.setupwizardlib.IInitialLockSetupService; 30 import com.android.car.setupwizardlib.InitialLockSetupConstants; 31 import com.android.car.setupwizardlib.InitialLockSetupConstants.LockTypes; 32 import com.android.car.setupwizardlib.InitialLockSetupConstants.SetLockCodes; 33 import com.android.car.setupwizardlib.InitialLockSetupConstants.ValidateLockFlags; 34 import com.android.car.setupwizardlib.LockConfig; 35 import com.android.internal.widget.LockPatternUtils; 36 import com.android.internal.widget.LockPatternView; 37 import com.android.internal.widget.LockscreenCredential; 38 39 import java.nio.charset.StandardCharsets; 40 import java.util.ArrayList; 41 import java.util.List; 42 43 /** 44 * Service that is used by Setup Wizard (exclusively) to set the initial lock screen. 45 * 46 * <p>This service provides functionality to get the lock config state, check if a password is 47 * valid based on the Settings defined password criteria, and save a lock if there is not one 48 * already saved. The interface for these operations is found in the {@link 49 * IInitialLockSetupService}. 50 */ 51 public class InitialLockSetupService extends Service { 52 53 private static final Logger LOG = new Logger(InitialLockSetupService.class); 54 private static final String SET_LOCK_PERMISSION = "com.android.car.settings.SET_INITIAL_LOCK"; 55 56 private final InitialLockSetupServiceImpl mIInitialLockSetupService = 57 new InitialLockSetupServiceImpl(); 58 59 /** 60 * Will return an {@link IBinder} for the service unless either the caller does not have the 61 * appropriate permissions or a lock has already been set on the device. In this case, the 62 * service will return {@code null}. 63 */ 64 @Override onBind(Intent intent)65 public IBinder onBind(Intent intent) { 66 LOG.v("onBind"); 67 if (checkCallingOrSelfPermission(SET_LOCK_PERMISSION) 68 != PackageManager.PERMISSION_GRANTED) { 69 // Check permission as a failsafe. 70 return null; 71 } 72 int userId = UserHandle.myUserId(); 73 LockPatternUtils lockPatternUtils = new LockPatternUtils(getApplicationContext()); 74 // Deny binding if there is an existing lock. 75 if (lockPatternUtils.getKeyguardStoredPasswordQuality(userId) 76 != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) { 77 LOG.v("Rejecting binding, lock exists"); 78 return null; 79 } 80 return mIInitialLockSetupService; 81 } 82 83 // Implementation of the service binder interface. 84 private class InitialLockSetupServiceImpl extends IInitialLockSetupService.Stub { 85 86 @Override getServiceVersion()87 public int getServiceVersion() { 88 return InitialLockSetupConstants.LIBRARY_VERSION; 89 } 90 91 @Override getLockConfig(@ockTypes int lockType)92 public LockConfig getLockConfig(@LockTypes int lockType) { 93 // All lock types currently are configured the same. 94 switch (lockType) { 95 case LockTypes.PASSWORD: 96 // fall through 97 case LockTypes.PIN: 98 // fall through 99 case LockTypes.PATTERN: 100 return new LockConfig(/* enabled= */ true, 101 LockPatternUtils.MIN_LOCK_PATTERN_SIZE); 102 } 103 return null; 104 } 105 byteArrayToPattern(byte[] bytes)106 private List<LockPatternView.Cell> byteArrayToPattern(byte[] bytes) { 107 if (bytes.length > 0 && bytes[0] <= 9) { 108 // Be compatible with old clients that incorrectly created the byte[] with cells 109 // numbered binary 1-9 instead of the LockPatternUtils convention of ASCII 1-9. 110 List<LockPatternView.Cell> pattern = new ArrayList<>(); 111 for (int i = 0; i < bytes.length; i++) { 112 pattern.add(LockPatternView.Cell.of( 113 (byte) ((bytes[i] - 1) / 3), (byte) ((bytes[i] - 1) % 3))); 114 } 115 return pattern; 116 } 117 return LockPatternUtils.byteArrayToPattern(bytes); 118 } 119 createLockscreenCredential( @ockTypes int lockType, byte[] password)120 private LockscreenCredential createLockscreenCredential( 121 @LockTypes int lockType, byte[] password) { 122 switch (lockType) { 123 case LockTypes.PASSWORD: 124 String passwordStr = new String(password, StandardCharsets.UTF_8); 125 return LockscreenCredential.createPassword(passwordStr); 126 case LockTypes.PIN: 127 String pinStr = new String(password, StandardCharsets.UTF_8); 128 return LockscreenCredential.createPin(pinStr); 129 case LockTypes.PATTERN: 130 List<LockPatternView.Cell> pattern = byteArrayToPattern(password); 131 return LockscreenCredential.createPattern(pattern); 132 default: 133 LOG.e("Unrecognized lockscreen credential type: " + lockType); 134 return null; 135 } 136 } 137 138 @Override 139 @ValidateLockFlags checkValidLock(@ockTypes int lockType, byte[] password)140 public int checkValidLock(@LockTypes int lockType, byte[] password) { 141 try (LockscreenCredential credential = createLockscreenCredential(lockType, password)) { 142 if (credential == null) { 143 return ValidateLockFlags.INVALID_GENERIC; 144 } 145 PasswordHelper helper = new PasswordHelper(getApplicationContext(), getUserId()); 146 if (!helper.validateCredential(credential)) { 147 return ValidateLockFlags.INVALID_GENERIC; 148 } 149 return 0; 150 } 151 } 152 153 @Override 154 @SetLockCodes setLock(@ockTypes int lockType, byte[] password)155 public int setLock(@LockTypes int lockType, byte[] password) { 156 int userId = UserHandle.myUserId(); 157 LockPatternUtils lockPatternUtils = new LockPatternUtils( 158 InitialLockSetupService.this.getApplicationContext()); 159 int currentPassword = lockPatternUtils.getKeyguardStoredPasswordQuality(userId); 160 if (currentPassword != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) { 161 LOG.v("Credential already set, rejecting call to setLock"); 162 return SetLockCodes.FAIL_LOCK_EXISTS; 163 } 164 try (LockscreenCredential credential = createLockscreenCredential(lockType, password)) { 165 if (credential == null) { 166 return SetLockCodes.FAIL_LOCK_INVALID; 167 } 168 PasswordHelper helper = new PasswordHelper(getApplicationContext(), userId); 169 if (!helper.validateCredential(credential)) { 170 LOG.v("Credential is not valid, rejecting call to setLock"); 171 return SetLockCodes.FAIL_LOCK_INVALID; 172 } 173 if (!lockPatternUtils.setLockCredential(credential, 174 /* savedCredential= */ LockscreenCredential.createNone(), userId)) { 175 return SetLockCodes.FAIL_LOCK_GENERIC; 176 } 177 return SetLockCodes.SUCCESS; 178 } catch (Exception e) { 179 LOG.e("Save lock exception", e); 180 return SetLockCodes.FAIL_LOCK_GENERIC; 181 } 182 } 183 184 @Override checkValidLockAndReturnError(@ockTypes int lockType, byte[] credentialBytes)185 public String checkValidLockAndReturnError(@LockTypes int lockType, 186 byte[] credentialBytes) { 187 try (LockscreenCredential credential = 188 createLockscreenCredential(lockType, credentialBytes)) { 189 if (credential == null) { 190 return getApplicationContext().getString(R.string.locktype_unavailable); 191 } 192 PasswordHelper helper = new PasswordHelper(getApplicationContext(), getUserId()); 193 helper.validateCredential(credential); 194 return helper.getCredentialValidationErrorMessages(); 195 } 196 } 197 } 198 } 199