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.car.userlib.CarUserManagerHelper;
23 import android.content.Intent;
24 import android.content.pm.PackageManager;
25 import android.os.IBinder;
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 
39 import java.util.ArrayList;
40 import java.util.Arrays;
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 = new CarUserManagerHelper(getApplicationContext()).getCurrentProcessUserId();
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     // Translates the byte[] pattern received into the List<LockPatternView.Cell> that is
84     // recognized by LockPatternUtils.
toSettingsPattern(byte[] pattern)85     private List<LockPatternView.Cell> toSettingsPattern(byte[] pattern) {
86         List<LockPatternView.Cell> outputList = new ArrayList<>();
87         for (int i = 0; i < pattern.length; i++) {
88             outputList.add(LockPatternView.Cell.of(
89                     InitialLockSetupHelper.getPatternCellRowFromByte(pattern[i]),
90                     InitialLockSetupHelper.getPatternCellColumnFromByte(pattern[i])));
91         }
92         return outputList;
93     }
94 
95     // Implementation of the service binder interface.
96     private class InitialLockSetupServiceImpl extends IInitialLockSetupService.Stub {
97 
98         @Override
getServiceVersion()99         public int getServiceVersion() {
100             return InitialLockSetupConstants.LIBRARY_VERSION;
101         }
102 
103         @Override
getLockConfig(@ockTypes int lockType)104         public LockConfig getLockConfig(@LockTypes int lockType) {
105             // All lock types currently are configured the same.
106             switch (lockType) {
107                 case LockTypes.PASSWORD:
108                     // fall through
109                 case LockTypes.PIN:
110                     // fall through
111                 case LockTypes.PATTERN:
112                     return new LockConfig(/* enabled= */true, PasswordHelper.MIN_LENGTH);
113             }
114             return null;
115         }
116 
117         @Override
118         @ValidateLockFlags
checkValidLock(@ockTypes int lockType, byte[] password)119         public int checkValidLock(@LockTypes int lockType, byte[] password) {
120             PasswordHelper passwordHelper;
121             switch (lockType) {
122                 case LockTypes.PASSWORD:
123                     passwordHelper = new PasswordHelper(/* isPin= */ false);
124                     return passwordHelper.validateSetupWizard(password);
125                 case LockTypes.PIN:
126                     passwordHelper = new PasswordHelper(/* isPin= */ true);
127                     return passwordHelper.validateSetupWizard(password);
128                 case LockTypes.PATTERN:
129                     return password.length >= LockPatternUtils.MIN_LOCK_PATTERN_SIZE
130                             ? 0 : ValidateLockFlags.INVALID_LENGTH;
131                 default:
132                     LOG.e("other lock type, returning generic error");
133                     return ValidateLockFlags.INVALID_GENERIC;
134             }
135         }
136 
137         @Override
138         @SetLockCodes
setLock(@ockTypes int lockType, byte[] password)139         public int setLock(@LockTypes int lockType, byte[] password) {
140             int userId = new CarUserManagerHelper(
141                     InitialLockSetupService.this.getApplicationContext())
142                     .getCurrentProcessUserId();
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("Password already set, rejecting call to setLock");
148                 return SetLockCodes.FAIL_LOCK_EXISTS;
149             }
150             if (!InitialLockSetupHelper.isValidLockResultCode(checkValidLock(lockType, password))) {
151                 LOG.v("Password is not valid, rejecting call to setLock");
152                 return SetLockCodes.FAIL_LOCK_INVALID;
153             }
154 
155             boolean success = false;
156             try {
157                 switch (lockType) {
158                     case LockTypes.PASSWORD:
159                         // Need to remove setup wizard lib byte array encoding and use the
160                         // LockPatternUtils encoding.
161                         byte[] encodedPassword = LockPatternUtils.charSequenceToByteArray(
162                                 InitialLockSetupHelper.byteArrayToCharSequence(password));
163                         lockPatternUtils.saveLockPassword(encodedPassword,
164                                 /* savedPassword= */ null,
165                                 DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC, 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                         byte[] encodedPin = LockPatternUtils.charSequenceToByteArray(
172                                 InitialLockSetupHelper.byteArrayToCharSequence(password));
173                         lockPatternUtils.saveLockPassword(encodedPin, /* savedPassword= */ null,
174                                 DevicePolicyManager.PASSWORD_QUALITY_NUMERIC, userId);
175                         success = true;
176                         break;
177                     case LockTypes.PATTERN:
178                         // Need to remove the setup wizard lib pattern encoding and use the
179                         // LockPatternUtils pattern format.
180                         List<LockPatternView.Cell> pattern = toSettingsPattern(password);
181                         lockPatternUtils.saveLockPattern(pattern, /* savedPattern =*/ null,
182                                 userId, /* allowUntrustedChange =*/ false);
183                         pattern.clear();
184                         success = true;
185                         break;
186                     default:
187                         LOG.e("Unknown lock type, returning a failure");
188                 }
189             } catch (Exception e) {
190                 LOG.e("Save lock exception", e);
191                 success = false;
192             }
193             Arrays.fill(password, (byte) 0);
194             return success ? SetLockCodes.SUCCESS : SetLockCodes.FAIL_LOCK_GENERIC;
195         }
196     }
197 }
198