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 
20 import android.app.Service;
21 import android.app.admin.DevicePolicyManager;
22 import android.content.Intent;
23 import android.content.pm.PackageManager;
24 import android.os.IBinder;
25 import android.os.UserHandle;
26 
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.InitialLockSetupHelper;
35 import com.android.car.setupwizardlib.LockConfig;
36 import com.android.internal.widget.LockPatternUtils;
37 import com.android.internal.widget.LockPatternView;
38 import com.android.internal.widget.LockscreenCredential;
39 
40 import java.util.ArrayList;
41 import java.util.Arrays;
42 import java.util.List;
43 
44 /**
45  * Service that is used by Setup Wizard (exclusively) to set the initial lock screen.
46  *
47  * <p>This service provides functionality to get the lock config state, check if a password is
48  * valid based on the Settings defined password criteria, and save a lock if there is not one
49  * already saved. The interface for these operations is found in the {@link
50  * IInitialLockSetupService}.
51  */
52 public class InitialLockSetupService extends Service {
53 
54     private static final Logger LOG = new Logger(InitialLockSetupService.class);
55     private static final String SET_LOCK_PERMISSION = "com.android.car.settings.SET_INITIAL_LOCK";
56 
57     private final InitialLockSetupServiceImpl mIInitialLockSetupService =
58             new InitialLockSetupServiceImpl();
59 
60     /**
61      * Will return an {@link IBinder} for the service unless either the caller does not have the
62      * appropriate permissions or a lock has already been set on the device. In this case, the
63      * service will return {@code null}.
64      */
65     @Override
onBind(Intent intent)66     public IBinder onBind(Intent intent) {
67         LOG.v("onBind");
68         if (checkCallingOrSelfPermission(SET_LOCK_PERMISSION)
69                 != PackageManager.PERMISSION_GRANTED) {
70             // Check permission as a failsafe.
71             return null;
72         }
73         int userId = UserHandle.myUserId();
74         LockPatternUtils lockPatternUtils = new LockPatternUtils(getApplicationContext());
75         // Deny binding if there is an existing lock.
76         if (lockPatternUtils.getKeyguardStoredPasswordQuality(userId)
77                 != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
78             LOG.v("Rejecting binding, lock exists");
79             return null;
80         }
81         return mIInitialLockSetupService;
82     }
83 
84     // Translates the byte[] pattern received into the List<LockPatternView.Cell> that is
85     // recognized by LockPatternUtils.
toSettingsPattern(byte[] pattern)86     private List<LockPatternView.Cell> toSettingsPattern(byte[] pattern) {
87         List<LockPatternView.Cell> outputList = new ArrayList<>();
88         for (int i = 0; i < pattern.length; i++) {
89             outputList.add(LockPatternView.Cell.of(
90                     InitialLockSetupHelper.getPatternCellRowFromByte(pattern[i]),
91                     InitialLockSetupHelper.getPatternCellColumnFromByte(pattern[i])));
92         }
93         return outputList;
94     }
95 
96     // Implementation of the service binder interface.
97     private class InitialLockSetupServiceImpl extends IInitialLockSetupService.Stub {
98 
99         @Override
getServiceVersion()100         public int getServiceVersion() {
101             return InitialLockSetupConstants.LIBRARY_VERSION;
102         }
103 
104         @Override
getLockConfig(@ockTypes int lockType)105         public LockConfig getLockConfig(@LockTypes int lockType) {
106             // All lock types currently are configured the same.
107             switch (lockType) {
108                 case LockTypes.PASSWORD:
109                     // fall through
110                 case LockTypes.PIN:
111                     // fall through
112                 case LockTypes.PATTERN:
113                     return new LockConfig(/* enabled= */ true, PasswordHelper.MIN_LENGTH);
114             }
115             return null;
116         }
117 
118         @Override
119         @ValidateLockFlags
checkValidLock(@ockTypes int lockType, byte[] password)120         public int checkValidLock(@LockTypes int lockType, byte[] password) {
121             PasswordHelper passwordHelper;
122             switch (lockType) {
123                 case LockTypes.PASSWORD:
124                     passwordHelper = new PasswordHelper(/* isPin= */ false);
125                     return passwordHelper.validateSetupWizard(password);
126                 case LockTypes.PIN:
127                     passwordHelper = new PasswordHelper(/* isPin= */ true);
128                     return passwordHelper.validateSetupWizard(password);
129                 case LockTypes.PATTERN:
130                     return password.length >= LockPatternUtils.MIN_LOCK_PATTERN_SIZE
131                             ? 0 : ValidateLockFlags.INVALID_LENGTH;
132                 default:
133                     LOG.e("other lock type, returning generic error");
134                     return ValidateLockFlags.INVALID_GENERIC;
135             }
136         }
137 
138         @Override
139         @SetLockCodes
setLock(@ockTypes int lockType, byte[] password)140         public int setLock(@LockTypes int lockType, byte[] password) {
141             int userId = UserHandle.myUserId();
142             LockPatternUtils lockPatternUtils = new LockPatternUtils(
143                     InitialLockSetupService.this.getApplicationContext());
144             int currentPassword = lockPatternUtils.getKeyguardStoredPasswordQuality(userId);
145             if (currentPassword != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
146                 LOG.v("Password already set, rejecting call to setLock");
147                 return SetLockCodes.FAIL_LOCK_EXISTS;
148             }
149             if (!InitialLockSetupHelper.isValidLockResultCode(checkValidLock(lockType, password))) {
150                 LOG.v("Password is not valid, rejecting call to setLock");
151                 return SetLockCodes.FAIL_LOCK_INVALID;
152             }
153 
154             boolean success = false;
155             try {
156                 switch (lockType) {
157                     case LockTypes.PASSWORD:
158                         // Need to remove setup wizard lib byte array encoding and use the
159                         // LockPatternUtils encoding.
160                         CharSequence passwordStr =
161                                 InitialLockSetupHelper.byteArrayToCharSequence(password);
162                         lockPatternUtils.setLockCredential(
163                                 LockscreenCredential.createPassword(passwordStr),
164                                 /* savedPassword= */ LockscreenCredential.createNone(),
165                                 userId);
166                         success = true;
167                         break;
168                     case LockTypes.PIN:
169                         // Need to remove setup wizard lib byte array encoding and use the
170                         // LockPatternUtils encoding.
171                         CharSequence pinStr =
172                                 InitialLockSetupHelper.byteArrayToCharSequence(password);
173                         lockPatternUtils.setLockCredential(
174                                 LockscreenCredential.createPin(pinStr),
175                                 /* savedPassword= */ LockscreenCredential.createNone(),
176                                 userId);
177                         success = true;
178                         break;
179                     case LockTypes.PATTERN:
180                         // Need to remove the setup wizard lib pattern encoding and use the
181                         // LockPatternUtils pattern format.
182                         List<LockPatternView.Cell> pattern = toSettingsPattern(password);
183                         lockPatternUtils.setLockCredential(
184                                 LockscreenCredential.createPattern(pattern),
185                                 /* savedPassword= */ LockscreenCredential.createNone(),
186                                 userId);
187                         pattern.clear();
188                         success = true;
189                         break;
190                     default:
191                         LOG.e("Unknown lock type, returning a failure");
192                 }
193             } catch (Exception e) {
194                 LOG.e("Save lock exception", e);
195                 success = false;
196             }
197             Arrays.fill(password, (byte) 0);
198             return success ? SetLockCodes.SUCCESS : SetLockCodes.FAIL_LOCK_GENERIC;
199         }
200     }
201 }
202