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