/* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License */ package com.android.server.locksettings; import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC; import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC; import static com.android.internal.widget.LockPatternUtils.stringToPattern; import android.app.ActivityManager; import android.os.ShellCommand; import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.LockPatternUtils.RequestThrottledException; import java.io.PrintWriter; class LockSettingsShellCommand extends ShellCommand { private static final String COMMAND_SET_PATTERN = "set-pattern"; private static final String COMMAND_SET_PIN = "set-pin"; private static final String COMMAND_SET_PASSWORD = "set-password"; private static final String COMMAND_CLEAR = "clear"; private static final String COMMAND_SP = "sp"; private static final String COMMAND_SET_DISABLED = "set-disabled"; private static final String COMMAND_VERIFY = "verify"; private static final String COMMAND_GET_DISABLED = "get-disabled"; private static final String COMMAND_HELP = "help"; private int mCurrentUserId; private final LockPatternUtils mLockPatternUtils; private String mOld = ""; private String mNew = ""; LockSettingsShellCommand(LockPatternUtils lockPatternUtils) { mLockPatternUtils = lockPatternUtils; } @Override public int onCommand(String cmd) { if (cmd == null) { return handleDefaultCommands(cmd); } try { mCurrentUserId = ActivityManager.getService().getCurrentUser().id; parseArgs(); if (!mLockPatternUtils.hasSecureLockScreen()) { switch (cmd) { case COMMAND_HELP: case COMMAND_GET_DISABLED: case COMMAND_SET_DISABLED: break; default: getErrPrintWriter().println( "The device does not support lock screen - ignoring the command."); return -1; } } if (!checkCredential()) { return -1; } switch (cmd) { case COMMAND_SET_PATTERN: runSetPattern(); break; case COMMAND_SET_PASSWORD: runSetPassword(); break; case COMMAND_SET_PIN: runSetPin(); break; case COMMAND_CLEAR: runClear(); break; case COMMAND_SP: runChangeSp(); break; case COMMAND_SET_DISABLED: runSetDisabled(); break; case COMMAND_VERIFY: runVerify(); break; case COMMAND_GET_DISABLED: runGetDisabled(); break; case COMMAND_HELP: onHelp(); break; default: getErrPrintWriter().println("Unknown command: " + cmd); break; } return 0; } catch (Exception e) { getErrPrintWriter().println("Error while executing command: " + cmd); e.printStackTrace(getErrPrintWriter()); return -1; } } private void runVerify() { // The command is only run if the credential is correct. getOutPrintWriter().println("Lock credential verified successfully"); } @Override public void onHelp() { try (final PrintWriter pw = getOutPrintWriter();) { pw.println("lockSettings service commands:"); pw.println(""); pw.println("NOTE: when lock screen is set, all commands require the --old " + " argument."); pw.println(""); pw.println(" help"); pw.println(" Prints this help text."); pw.println(""); pw.println(" get-disabled [--old ] [--user USER_ID]"); pw.println(" Checks whether lock screen is disabled."); pw.println(""); pw.println(" set-disabled [--old ] [--user USER_ID] "); pw.println(" When true, disables lock screen."); pw.println(""); pw.println(" set-pattern [--old ] [--user USER_ID] "); pw.println(" Sets the lock screen as pattern, using the given PATTERN to unlock."); pw.println(""); pw.println(" set-pin [--old ] [--user USER_ID] "); pw.println(" Sets the lock screen as PIN, using the given PIN to unlock."); pw.println(""); pw.println(" set-pin [--old ] [--user USER_ID] "); pw.println(" Sets the lock screen as password, using the given PASSOWRD to unlock."); pw.println(""); pw.println(" sp [--old ] [--user USER_ID]"); pw.println(" Gets whether synthetic password is enabled."); pw.println(""); pw.println(" sp [--old ] [--user USER_ID] <1|0>"); pw.println(" Enables / disables synthetic password."); pw.println(""); pw.println(" clear [--old ] [--user USER_ID]"); pw.println(" Clears the lock credentials."); pw.println(""); pw.println(" verify [--old ] [--user USER_ID]"); pw.println(" Verifies the lock credentials."); pw.println(""); } } private void parseArgs() { String opt; while ((opt = getNextOption()) != null) { if ("--old".equals(opt)) { mOld = getNextArgRequired(); } else if ("--user".equals(opt)) { mCurrentUserId = Integer.parseInt(getNextArgRequired()); } else { getErrPrintWriter().println("Unknown option: " + opt); throw new IllegalArgumentException(); } } mNew = getNextArg(); } private void runChangeSp() { if (mNew != null ) { if ("1".equals(mNew)) { mLockPatternUtils.enableSyntheticPassword(); getOutPrintWriter().println("Synthetic password enabled"); } else if ("0".equals(mNew)) { mLockPatternUtils.disableSyntheticPassword(); getOutPrintWriter().println("Synthetic password disabled"); } } getOutPrintWriter().println(String.format("SP Enabled = %b", mLockPatternUtils.isSyntheticPasswordEnabled())); } private void runSetPattern() { byte[] oldBytes = mOld != null ? mOld.getBytes() : null; mLockPatternUtils.saveLockPattern(stringToPattern(mNew), oldBytes, mCurrentUserId); getOutPrintWriter().println("Pattern set to '" + mNew + "'"); } private void runSetPassword() { byte[] newBytes = mNew != null ? mNew.getBytes() : null; byte[] oldBytes = mOld != null ? mOld.getBytes() : null; mLockPatternUtils.saveLockPassword(newBytes, oldBytes, PASSWORD_QUALITY_ALPHABETIC, mCurrentUserId); getOutPrintWriter().println("Password set to '" + mNew + "'"); } private void runSetPin() { byte[] newBytes = mNew != null ? mNew.getBytes() : null; byte[] oldBytes = mOld != null ? mOld.getBytes() : null; mLockPatternUtils.saveLockPassword(newBytes, oldBytes, PASSWORD_QUALITY_NUMERIC, mCurrentUserId); getOutPrintWriter().println("Pin set to '" + mNew + "'"); } private void runClear() { byte[] oldBytes = mOld != null ? mOld.getBytes() : null; mLockPatternUtils.clearLock(oldBytes, mCurrentUserId); getOutPrintWriter().println("Lock credential cleared"); } private void runSetDisabled() { final boolean disabled = Boolean.parseBoolean(mNew); mLockPatternUtils.setLockScreenDisabled(disabled, mCurrentUserId); getOutPrintWriter().println("Lock screen disabled set to " + disabled); } private void runGetDisabled() { boolean isLockScreenDisabled = mLockPatternUtils.isLockScreenDisabled(mCurrentUserId); getOutPrintWriter().println(isLockScreenDisabled); } private boolean checkCredential() { final boolean havePassword = mLockPatternUtils.isLockPasswordEnabled(mCurrentUserId); final boolean havePattern = mLockPatternUtils.isLockPatternEnabled(mCurrentUserId); if (havePassword || havePattern) { if (mLockPatternUtils.isManagedProfileWithUnifiedChallenge(mCurrentUserId)) { getOutPrintWriter().println("Profile uses unified challenge"); return false; } try { final boolean result; if (havePassword) { byte[] passwordBytes = mOld != null ? mOld.getBytes() : null; result = mLockPatternUtils.checkPassword(passwordBytes, mCurrentUserId); } else { result = mLockPatternUtils.checkPattern(stringToPattern(mOld), mCurrentUserId); } if (!result) { if (!mLockPatternUtils.isManagedProfileWithUnifiedChallenge(mCurrentUserId)) { mLockPatternUtils.reportFailedPasswordAttempt(mCurrentUserId); } getOutPrintWriter().println("Old password '" + mOld + "' didn't match"); } else { // Resets the counter for failed password attempts to 0. mLockPatternUtils.reportSuccessfulPasswordAttempt(mCurrentUserId); } return result; } catch (RequestThrottledException e) { getOutPrintWriter().println("Request throttled"); return false; } } else { if (!mOld.isEmpty()) { getOutPrintWriter().println("Old password provided but user has no password"); return false; } return true; } } }