Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fd869cfe authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Add ability to modify credential via shell command"

parents c62ca218 2fef6f7b
Loading
Loading
Loading
Loading
+30 −0
Original line number Diff line number Diff line
# 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.

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_MODULE := locksettings
LOCAL_MODULE_TAGS := optional
include $(BUILD_JAVA_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := locksettings
LOCAL_SRC_FILES := locksettings
LOCAL_MODULE_CLASS := EXECUTABLES
LOCAL_MODULE_TAGS := optional
include $(BUILD_PREBUILT)

+5 −0
Original line number Diff line number Diff line
# Script to start "locksettings" on the device
#
base=/system
export CLASSPATH=$base/framework/locksettings.jar
exec app_process $base/bin com.android.commands.locksettings.LockSettingsCmd "$@"
+65 −0
Original line number Diff line number Diff line
/*
 * 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.commands.locksettings;

import android.os.ResultReceiver;
import android.os.ServiceManager;
import android.os.ShellCallback;

import com.android.internal.os.BaseCommand;
import com.android.internal.widget.ILockSettings;

import java.io.FileDescriptor;
import java.io.PrintStream;

public final class LockSettingsCmd extends BaseCommand {

    private static final String USAGE =
            "usage: locksettings set-pattern [--old OLD_CREDENTIAL] NEW_PATTERN\n" +
            "       locksettings set-pin [--old OLD_CREDENTIAL] NEW_PIN\n" +
            "       locksettings set-password [--old OLD_CREDENTIAL] NEW_PASSWORD\n" +
            "       locksettings clear [--old OLD_CREDENTIAL]\n" +
            "\n" +
            "locksettings set-pattern: sets a pattern\n" +
            "    A pattern is specified by a non-separated list of numbers that index the cell\n" +
            "    on the pattern in a 1-based manner in left to right and top to bottom order,\n" +
            "    i.e. the top-left cell is indexed with 1, whereas the bottom-right cell\n" +
            "    is indexed with 9. Example: 1234\n" +
            "\n" +
            "locksettings set-pin: sets a PIN\n" +
            "\n" +
            "locksettings set-password: sets a password\n" +
            "\n" +
            "locksettings clear: clears the unlock credential\n";

    public static void main(String[] args) {
        (new LockSettingsCmd()).run(args);
    }

    @Override
    public void onShowUsage(PrintStream out) {
        out.println(USAGE);
    }

    @Override
    public void onRun() throws Exception {
        ILockSettings lockSettings = ILockSettings.Stub.asInterface(
                ServiceManager.getService("lock_settings"));
        lockSettings.asBinder().shellCommand(FileDescriptor.in, FileDescriptor.out,
                FileDescriptor.err, getRawArgs(), new ShellCallback(), new ResultReceiver(null) {});
    }
}
+28 −0
Original line number Diff line number Diff line
@@ -49,6 +49,8 @@ import android.os.IProgressListener;
import android.os.Parcel;
import android.os.Process;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ShellCallback;
import android.os.storage.IMountService;
import android.os.storage.StorageManager;
import android.os.ServiceManager;
@@ -79,6 +81,7 @@ import com.android.server.LockSettingsStorage.CredentialHash;
import libcore.util.HexEncoding;

import java.io.ByteArrayOutputStream;
import java.io.FileDescriptor;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
@@ -1585,6 +1588,31 @@ public class LockSettingsService extends ILockSettings.Stub {
        return mStrongAuthTracker.getStrongAuthForUser(userId);
    }

    private boolean isCallerShell() {
        final int callingUid = Binder.getCallingUid();
        return callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID;
    }

    private void enforceShell() {
        if (!isCallerShell()) {
            throw new SecurityException("Caller must be shell");
        }
    }

    @Override
    public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
            String[] args, ShellCallback callback, ResultReceiver resultReceiver)
            throws RemoteException {
        enforceShell();
        final long origId = Binder.clearCallingIdentity();
        try {
            (new LockSettingsShellCommand(mContext, new LockPatternUtils(mContext))).exec(
                    this, in, out, err, args, callback, resultReceiver);
        } finally {
            Binder.restoreCallingIdentity(origId);
        }
    }

    private static final String[] VALID_SETTINGS = new String[] {
        LockPatternUtils.LOCKOUT_PERMANENT_KEY,
        LockPatternUtils.LOCKOUT_ATTEMPT_DEADLINE,
+143 −0
Original line number Diff line number Diff line
/*
 * 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;

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.ActivityManagerNative;
import android.content.Context;
import android.os.Binder;
import android.os.Process;
import android.os.RemoteException;
import android.os.ShellCommand;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.LockPatternUtils.RequestThrottledException;

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 int mCurrentUserId;
    private final LockPatternUtils mLockPatternUtils;
    private final Context mContext;
    private String mOld = "";
    private String mNew = "";

    LockSettingsShellCommand(Context context, LockPatternUtils lockPatternUtils) {
        mContext = context;
        mLockPatternUtils = lockPatternUtils;
    }

    @Override
    public int onCommand(String cmd) {
        try {
            mCurrentUserId = ActivityManagerNative.getDefault().getCurrentUser().id;

            parseArgs();
            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;
                default:
                    getErrPrintWriter().println("Unknown command: " + cmd);
                    break;
            }
            return 0;
        } catch (Exception e) {
            getErrPrintWriter().println("Error while executing command: " + e);
            return -1;
        }
    }

    @Override
    public void onHelp() {
    }

    private void parseArgs() {
        String opt;
        while ((opt = getNextOption()) != null) {
            if ("--old".equals(opt)) {
                mOld = getNextArgRequired();
            } else {
                getErrPrintWriter().println("Unknown option: " + opt);
                throw new IllegalArgumentException();
            }
        }
        mNew = getNextArg();
    }

    private void runSetPattern() throws RemoteException {
        mLockPatternUtils.saveLockPattern(stringToPattern(mNew), mOld, mCurrentUserId);
        getOutPrintWriter().println("Pattern set to '" + mNew + "'");
    }

    private void runSetPassword() throws RemoteException {
        mLockPatternUtils.saveLockPassword(mNew, mOld, PASSWORD_QUALITY_ALPHABETIC, mCurrentUserId);
        getOutPrintWriter().println("Password set to '" + mNew + "'");
    }

    private void runSetPin() throws RemoteException {
        mLockPatternUtils.saveLockPassword(mNew, mOld, PASSWORD_QUALITY_NUMERIC, mCurrentUserId);
        getOutPrintWriter().println("Pin set to '" + mNew + "'");
    }

    private void runClear() throws RemoteException {
        mLockPatternUtils.clearLock(mCurrentUserId);
        getOutPrintWriter().println("Lock credential cleared");
    }

    private boolean checkCredential() throws RemoteException, RequestThrottledException {
        final boolean havePassword = mLockPatternUtils.isLockPasswordEnabled(mCurrentUserId);
        final boolean havePattern = mLockPatternUtils.isLockPatternEnabled(mCurrentUserId);
        if (havePassword || havePattern) {
            boolean result;
            if (havePassword) {
                result = mLockPatternUtils.checkPassword(mOld, mCurrentUserId);
            } else {
                result = mLockPatternUtils.checkPattern(stringToPattern(mOld),
                        mCurrentUserId);
            }
            if (result) {
                return true;
            } else {
                getOutPrintWriter().println("Old password '" + mOld + "' didn't match");
                return false;
            }
        } else {
            return true;
        }
    }
}
Loading