1 /* 2 * Copyright (C) 2016 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.server.locksettings; 18 19 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC; 20 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC; 21 22 import static com.android.internal.widget.LockPatternUtils.stringToPattern; 23 24 import android.app.ActivityManager; 25 import android.os.ShellCommand; 26 27 import com.android.internal.widget.LockPatternUtils; 28 import com.android.internal.widget.LockPatternUtils.RequestThrottledException; 29 30 import java.io.PrintWriter; 31 32 class LockSettingsShellCommand extends ShellCommand { 33 34 private static final String COMMAND_SET_PATTERN = "set-pattern"; 35 private static final String COMMAND_SET_PIN = "set-pin"; 36 private static final String COMMAND_SET_PASSWORD = "set-password"; 37 private static final String COMMAND_CLEAR = "clear"; 38 private static final String COMMAND_SP = "sp"; 39 private static final String COMMAND_SET_DISABLED = "set-disabled"; 40 private static final String COMMAND_VERIFY = "verify"; 41 private static final String COMMAND_GET_DISABLED = "get-disabled"; 42 private static final String COMMAND_HELP = "help"; 43 44 private int mCurrentUserId; 45 private final LockPatternUtils mLockPatternUtils; 46 private String mOld = ""; 47 private String mNew = ""; 48 LockSettingsShellCommand(LockPatternUtils lockPatternUtils)49 LockSettingsShellCommand(LockPatternUtils lockPatternUtils) { 50 mLockPatternUtils = lockPatternUtils; 51 } 52 53 @Override onCommand(String cmd)54 public int onCommand(String cmd) { 55 if (cmd == null) { 56 return handleDefaultCommands(cmd); 57 } 58 try { 59 mCurrentUserId = ActivityManager.getService().getCurrentUser().id; 60 61 parseArgs(); 62 if (!mLockPatternUtils.hasSecureLockScreen()) { 63 switch (cmd) { 64 case COMMAND_HELP: 65 case COMMAND_GET_DISABLED: 66 case COMMAND_SET_DISABLED: 67 break; 68 default: 69 getErrPrintWriter().println( 70 "The device does not support lock screen - ignoring the command."); 71 return -1; 72 } 73 } 74 if (!checkCredential()) { 75 return -1; 76 } 77 switch (cmd) { 78 case COMMAND_SET_PATTERN: 79 runSetPattern(); 80 break; 81 case COMMAND_SET_PASSWORD: 82 runSetPassword(); 83 break; 84 case COMMAND_SET_PIN: 85 runSetPin(); 86 break; 87 case COMMAND_CLEAR: 88 runClear(); 89 break; 90 case COMMAND_SP: 91 runChangeSp(); 92 break; 93 case COMMAND_SET_DISABLED: 94 runSetDisabled(); 95 break; 96 case COMMAND_VERIFY: 97 runVerify(); 98 break; 99 case COMMAND_GET_DISABLED: 100 runGetDisabled(); 101 break; 102 case COMMAND_HELP: 103 onHelp(); 104 break; 105 default: 106 getErrPrintWriter().println("Unknown command: " + cmd); 107 break; 108 } 109 return 0; 110 } catch (Exception e) { 111 getErrPrintWriter().println("Error while executing command: " + cmd); 112 e.printStackTrace(getErrPrintWriter()); 113 return -1; 114 } 115 } 116 runVerify()117 private void runVerify() { 118 // The command is only run if the credential is correct. 119 getOutPrintWriter().println("Lock credential verified successfully"); 120 } 121 122 @Override onHelp()123 public void onHelp() { 124 try (final PrintWriter pw = getOutPrintWriter();) { 125 pw.println("lockSettings service commands:"); 126 pw.println(""); 127 pw.println("NOTE: when lock screen is set, all commands require the --old <CREDENTIAL>" 128 + " argument."); 129 pw.println(""); 130 pw.println(" help"); 131 pw.println(" Prints this help text."); 132 pw.println(""); 133 pw.println(" get-disabled [--old <CREDENTIAL>] [--user USER_ID]"); 134 pw.println(" Checks whether lock screen is disabled."); 135 pw.println(""); 136 pw.println(" set-disabled [--old <CREDENTIAL>] [--user USER_ID] <true|false>"); 137 pw.println(" When true, disables lock screen."); 138 pw.println(""); 139 pw.println(" set-pattern [--old <CREDENTIAL>] [--user USER_ID] <PATTERN>"); 140 pw.println(" Sets the lock screen as pattern, using the given PATTERN to unlock."); 141 pw.println(""); 142 pw.println(" set-pin [--old <CREDENTIAL>] [--user USER_ID] <PIN>"); 143 pw.println(" Sets the lock screen as PIN, using the given PIN to unlock."); 144 pw.println(""); 145 pw.println(" set-pin [--old <CREDENTIAL>] [--user USER_ID] <PASSWORD>"); 146 pw.println(" Sets the lock screen as password, using the given PASSOWRD to unlock."); 147 pw.println(""); 148 pw.println(" sp [--old <CREDENTIAL>] [--user USER_ID]"); 149 pw.println(" Gets whether synthetic password is enabled."); 150 pw.println(""); 151 pw.println(" sp [--old <CREDENTIAL>] [--user USER_ID] <1|0>"); 152 pw.println(" Enables / disables synthetic password."); 153 pw.println(""); 154 pw.println(" clear [--old <CREDENTIAL>] [--user USER_ID]"); 155 pw.println(" Clears the lock credentials."); 156 pw.println(""); 157 pw.println(" verify [--old <CREDENTIAL>] [--user USER_ID]"); 158 pw.println(" Verifies the lock credentials."); 159 pw.println(""); 160 } 161 } 162 parseArgs()163 private void parseArgs() { 164 String opt; 165 while ((opt = getNextOption()) != null) { 166 if ("--old".equals(opt)) { 167 mOld = getNextArgRequired(); 168 } else if ("--user".equals(opt)) { 169 mCurrentUserId = Integer.parseInt(getNextArgRequired()); 170 } else { 171 getErrPrintWriter().println("Unknown option: " + opt); 172 throw new IllegalArgumentException(); 173 } 174 } 175 mNew = getNextArg(); 176 } 177 runChangeSp()178 private void runChangeSp() { 179 if (mNew != null ) { 180 if ("1".equals(mNew)) { 181 mLockPatternUtils.enableSyntheticPassword(); 182 getOutPrintWriter().println("Synthetic password enabled"); 183 } else if ("0".equals(mNew)) { 184 mLockPatternUtils.disableSyntheticPassword(); 185 getOutPrintWriter().println("Synthetic password disabled"); 186 } 187 } 188 getOutPrintWriter().println(String.format("SP Enabled = %b", 189 mLockPatternUtils.isSyntheticPasswordEnabled())); 190 } 191 runSetPattern()192 private void runSetPattern() { 193 byte[] oldBytes = mOld != null ? mOld.getBytes() : null; 194 mLockPatternUtils.saveLockPattern(stringToPattern(mNew), oldBytes, mCurrentUserId); 195 getOutPrintWriter().println("Pattern set to '" + mNew + "'"); 196 } 197 runSetPassword()198 private void runSetPassword() { 199 byte[] newBytes = mNew != null ? mNew.getBytes() : null; 200 byte[] oldBytes = mOld != null ? mOld.getBytes() : null; 201 mLockPatternUtils.saveLockPassword(newBytes, oldBytes, PASSWORD_QUALITY_ALPHABETIC, 202 mCurrentUserId); 203 getOutPrintWriter().println("Password set to '" + mNew + "'"); 204 } 205 runSetPin()206 private void runSetPin() { 207 byte[] newBytes = mNew != null ? mNew.getBytes() : null; 208 byte[] oldBytes = mOld != null ? mOld.getBytes() : null; 209 mLockPatternUtils.saveLockPassword(newBytes, oldBytes, PASSWORD_QUALITY_NUMERIC, 210 mCurrentUserId); 211 getOutPrintWriter().println("Pin set to '" + mNew + "'"); 212 } 213 runClear()214 private void runClear() { 215 byte[] oldBytes = mOld != null ? mOld.getBytes() : null; 216 mLockPatternUtils.clearLock(oldBytes, mCurrentUserId); 217 getOutPrintWriter().println("Lock credential cleared"); 218 } 219 runSetDisabled()220 private void runSetDisabled() { 221 final boolean disabled = Boolean.parseBoolean(mNew); 222 mLockPatternUtils.setLockScreenDisabled(disabled, mCurrentUserId); 223 getOutPrintWriter().println("Lock screen disabled set to " + disabled); 224 } 225 runGetDisabled()226 private void runGetDisabled() { 227 boolean isLockScreenDisabled = mLockPatternUtils.isLockScreenDisabled(mCurrentUserId); 228 getOutPrintWriter().println(isLockScreenDisabled); 229 } 230 checkCredential()231 private boolean checkCredential() { 232 final boolean havePassword = mLockPatternUtils.isLockPasswordEnabled(mCurrentUserId); 233 final boolean havePattern = mLockPatternUtils.isLockPatternEnabled(mCurrentUserId); 234 if (havePassword || havePattern) { 235 if (mLockPatternUtils.isManagedProfileWithUnifiedChallenge(mCurrentUserId)) { 236 getOutPrintWriter().println("Profile uses unified challenge"); 237 return false; 238 } 239 240 try { 241 final boolean result; 242 if (havePassword) { 243 byte[] passwordBytes = mOld != null ? mOld.getBytes() : null; 244 result = mLockPatternUtils.checkPassword(passwordBytes, mCurrentUserId); 245 } else { 246 result = mLockPatternUtils.checkPattern(stringToPattern(mOld), mCurrentUserId); 247 } 248 if (!result) { 249 if (!mLockPatternUtils.isManagedProfileWithUnifiedChallenge(mCurrentUserId)) { 250 mLockPatternUtils.reportFailedPasswordAttempt(mCurrentUserId); 251 } 252 getOutPrintWriter().println("Old password '" + mOld + "' didn't match"); 253 } else { 254 // Resets the counter for failed password attempts to 0. 255 mLockPatternUtils.reportSuccessfulPasswordAttempt(mCurrentUserId); 256 } 257 return result; 258 } catch (RequestThrottledException e) { 259 getOutPrintWriter().println("Request throttled"); 260 return false; 261 } 262 } else { 263 if (!mOld.isEmpty()) { 264 getOutPrintWriter().println("Old password provided but user has no password"); 265 return false; 266 } 267 return true; 268 } 269 } 270 } 271