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

Commit dc17915c authored by Eric Biggers's avatar Eric Biggers Committed by Automerger Merge Worker
Browse files

Add a verification flow for the user to exit repair mode am: 1c95758c

parents 0142d3d6 1c95758c
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -125,6 +125,15 @@ public class KeyguardManager {
    public static final String ACTION_PREPARE_REPAIR_MODE_DEVICE_CREDENTIAL =
            "android.app.action.PREPARE_REPAIR_MODE_DEVICE_CREDENTIAL";

    /**
     * Intent used to prompt user for device credential that is written by
     * {@link #ACTION_PREPARE_REPAIR_MODE_DEVICE_CREDENTIAL} for exiting
     * repair mode.
     * @hide
     */
    public static final String ACTION_CONFIRM_REPAIR_MODE_DEVICE_CREDENTIAL =
            "android.app.action.CONFIRM_REPAIR_MODE_DEVICE_CREDENTIAL";

    /**
     * A CharSequence dialog title to show to the user when used with a
     * {@link #ACTION_CONFIRM_DEVICE_CREDENTIAL}.
+53 −9
Original line number Diff line number Diff line
@@ -180,6 +180,11 @@ public class LockPatternUtils {
     */
    public static final int USER_FRP = UserHandle.USER_NULL + 1;

    /**
     * Special user id for triggering the exiting repair mode verification flow.
     */
    public static final int USER_REPAIR_MODE = UserHandle.USER_NULL + 2;

    public final static String PASSWORD_TYPE_KEY = "lockscreen.password_type";
    @Deprecated
    public final static String PASSWORD_TYPE_ALTERNATE_KEY = "lockscreen.password_type_alternate";
@@ -399,7 +404,7 @@ public class LockPatternUtils {

    @UnsupportedAppUsage
    public void reportFailedPasswordAttempt(int userId) {
        if (userId == USER_FRP && frpCredentialEnabled(mContext)) {
        if (isSpecialUserId(mContext, userId, /* checkDeviceSupported= */ true)) {
            return;
        }
        getDevicePolicyManager().reportFailedPasswordAttempt(userId);
@@ -408,7 +413,7 @@ public class LockPatternUtils {

    @UnsupportedAppUsage
    public void reportSuccessfulPasswordAttempt(int userId) {
        if (userId == USER_FRP && frpCredentialEnabled(mContext)) {
        if (isSpecialUserId(mContext, userId, /* checkDeviceSupported= */ true)) {
            return;
        }
        getDevicePolicyManager().reportSuccessfulPasswordAttempt(userId);
@@ -416,21 +421,21 @@ public class LockPatternUtils {
    }

    public void reportPasswordLockout(int timeoutMs, int userId) {
        if (userId == USER_FRP && frpCredentialEnabled(mContext)) {
        if (isSpecialUserId(mContext, userId, /* checkDeviceSupported= */ true)) {
            return;
        }
        getTrustManager().reportUnlockLockout(timeoutMs, userId);
    }

    public int getCurrentFailedPasswordAttempts(int userId) {
        if (userId == USER_FRP && frpCredentialEnabled(mContext)) {
        if (isSpecialUserId(mContext, userId, /* checkDeviceSupported= */ true)) {
            return 0;
        }
        return getDevicePolicyManager().getCurrentFailedPasswordAttempts(userId);
    }

    public int getMaximumFailedPasswordsForWipe(int userId) {
        if (userId == USER_FRP && frpCredentialEnabled(mContext)) {
        if (isSpecialUserId(mContext, userId, /* checkDeviceSupported= */ true)) {
            return 0;
        }
        return getDevicePolicyManager().getMaximumFailedPasswordsForWipe(
@@ -750,6 +755,17 @@ public class LockPatternUtils {
        }
    }

    /** Returns the credential type corresponding to the given PIN or password quality. */
    public static int pinOrPasswordQualityToCredentialType(int quality) {
        if (isQualityAlphabeticPassword(quality)) {
            return CREDENTIAL_TYPE_PASSWORD;
        }
        if (isQualityNumericPin(quality)) {
            return CREDENTIAL_TYPE_PIN;
        }
        throw new IllegalArgumentException("Quality is neither Pin nor password: " + quality);
    }

    /**
     * Save a new lockscreen credential.
     *
@@ -982,7 +998,7 @@ public class LockPatternUtils {
                }
                @Override
                public boolean shouldBypassCache(Integer userHandle) {
                    return userHandle == USER_FRP;
                    return isSpecialUserId(userHandle);
                }
            };

@@ -1089,9 +1105,10 @@ public class LockPatternUtils {
    @UnsupportedAppUsage
    public long setLockoutAttemptDeadline(int userId, int timeoutMs) {
        final long deadline = SystemClock.elapsedRealtime() + timeoutMs;
        if (userId == USER_FRP) {
            // For secure password storage (that is required for FRP), the underlying storage also
            // enforces the deadline. Since we cannot store settings for the FRP user, don't.
        if (isSpecialUserId(userId)) {
            // For secure password storage (that is required for special users such as FRP), the
            // underlying storage also enforces the deadline. Since we cannot store settings
            // for special users, don't.
            return deadline;
        }
        mLockoutDeadlines.put(userId, deadline);
@@ -1860,6 +1877,33 @@ public class LockPatternUtils {
        return SystemProperties.getInt(GSI_RUNNING_PROP, 0) > 0;
    }

    /**
     * Return {@code true} if the given user id is a special user such as {@link #USER_FRP}.
     */
    public static boolean isSpecialUserId(int userId) {
        return isSpecialUserId(/* context= */ null, userId, /* checkDeviceSupported= */ false);
    }

    /**
     * Return {@code true} if the given user id is a special user for the verification flow.
     *
     * @param checkDeviceSupported {@code true} to check the specified user is supported
     *                             by the device.
     */
    private static boolean isSpecialUserId(@Nullable Context context, int userId,
            boolean checkDeviceSupported) {
        switch (userId) {
            case USER_FRP:
                if (checkDeviceSupported) return frpCredentialEnabled(context);
                return true;

            case USER_REPAIR_MODE:
                if (checkDeviceSupported) return isRepairModeSupported(context);
                return true;
        }
        return false;
    }

    /**
     * Attempt to rederive the unified work challenge for the specified profile user and unlock the
     * user. If successful, this would allow the user to leave quiet mode automatically without
+13 −0
Original line number Diff line number Diff line
@@ -36,6 +36,11 @@ public class LockPatternUtilsTest {
        assertTrue(LockPatternUtils.USER_FRP < 0);
    }

    @Test
    public void testUserRepairMode_isNotRegularUser() {
        assertTrue(LockPatternUtils.USER_REPAIR_MODE < 0);
    }

    @Test
    public void testUserFrp_isNotAReservedSpecialUser() throws Exception {
        assertNotEquals(UserHandle.USER_NULL, LockPatternUtils.USER_FRP);
@@ -43,4 +48,12 @@ public class LockPatternUtilsTest {
        assertNotEquals(UserHandle.USER_CURRENT, LockPatternUtils.USER_FRP);
        assertNotEquals(UserHandle.USER_CURRENT_OR_SELF, LockPatternUtils.USER_FRP);
    }

    @Test
    public void testUserRepairMode_isNotAReservedSpecialUser() throws Exception {
        assertNotEquals(UserHandle.USER_NULL, LockPatternUtils.USER_REPAIR_MODE);
        assertNotEquals(UserHandle.USER_ALL, LockPatternUtils.USER_REPAIR_MODE);
        assertNotEquals(UserHandle.USER_CURRENT, LockPatternUtils.USER_REPAIR_MODE);
        assertNotEquals(UserHandle.USER_CURRENT_OR_SELF, LockPatternUtils.USER_REPAIR_MODE);
    }
}
+14 −31
Original line number Diff line number Diff line
@@ -31,7 +31,6 @@ import static android.os.UserHandle.USER_ALL;
import static android.os.UserHandle.USER_SYSTEM;

import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD_OR_PIN;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PIN;
import static com.android.internal.widget.LockPatternUtils.CURRENT_LSKF_BASED_PROTECTOR_ID_KEY;
@@ -40,9 +39,12 @@ import static com.android.internal.widget.LockPatternUtils.PIN_LENGTH_UNAVAILABL
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE;
import static com.android.internal.widget.LockPatternUtils.USER_FRP;
import static com.android.internal.widget.LockPatternUtils.USER_REPAIR_MODE;
import static com.android.internal.widget.LockPatternUtils.VERIFY_FLAG_REQUEST_GK_PW_HANDLE;
import static com.android.internal.widget.LockPatternUtils.VERIFY_FLAG_WRITE_REPAIR_MODE_PW;
import static com.android.internal.widget.LockPatternUtils.frpCredentialEnabled;
import static com.android.internal.widget.LockPatternUtils.isSpecialUserId;
import static com.android.internal.widget.LockPatternUtils.pinOrPasswordQualityToCredentialType;
import static com.android.internal.widget.LockPatternUtils.userOwnsFrpCredential;
import static com.android.server.locksettings.SyntheticPasswordManager.TOKEN_TYPE_STRONG;
import static com.android.server.locksettings.SyntheticPasswordManager.TOKEN_TYPE_WEAK;
@@ -1315,8 +1317,8 @@ public class LockSettingsService extends ILockSettings.Stub {
     * {@link #CREDENTIAL_TYPE_PASSWORD}
     */
    private int getCredentialTypeInternal(int userId) {
        if (userId == USER_FRP) {
            return getFrpCredentialType();
        if (isSpecialUserId(userId)) {
            return mSpManager.getSpecialUserCredentialType(userId);
        }
        synchronized (mSpManager) {
            final long protectorId = getCurrentLskfBasedProtectorId(userId);
@@ -1332,29 +1334,6 @@ public class LockSettingsService extends ILockSettings.Stub {
        }
    }

    private int getFrpCredentialType() {
        PersistentData data = mStorage.readPersistentDataBlock();
        if (data.type != PersistentData.TYPE_SP_GATEKEEPER &&
                data.type != PersistentData.TYPE_SP_WEAVER) {
            return CREDENTIAL_TYPE_NONE;
        }
        int credentialType = SyntheticPasswordManager.getFrpCredentialType(data.payload);
        if (credentialType != CREDENTIAL_TYPE_PASSWORD_OR_PIN) {
            return credentialType;
        }
        return pinOrPasswordQualityToCredentialType(data.qualityForUi);
    }

    private static int pinOrPasswordQualityToCredentialType(int quality) {
        if (LockPatternUtils.isQualityAlphabeticPassword(quality)) {
            return CREDENTIAL_TYPE_PASSWORD;
        }
        if (LockPatternUtils.isQualityNumericPin(quality)) {
            return CREDENTIAL_TYPE_PIN;
        }
        throw new IllegalArgumentException("Quality is neither Pin nor password: " + quality);
    }

    private boolean isUserSecure(int userId) {
        return getCredentialTypeInternal(userId) != CREDENTIAL_TYPE_NONE;
    }
@@ -1596,8 +1575,8 @@ public class LockSettingsService extends ILockSettings.Stub {
     * unlock operation.
     */
    private void sendCredentialsOnUnlockIfRequired(LockscreenCredential credential, int userId) {
        // Don't send credentials during the factory reset protection flow.
        if (userId == USER_FRP) {
        // Don't send credentials during the special user flow.
        if (isSpecialUserId(userId)) {
            return;
        }

@@ -2218,15 +2197,19 @@ public class LockSettingsService extends ILockSettings.Stub {
            Slog.e(TAG, "FRP credential can only be verified prior to provisioning.");
            return VerifyCredentialResponse.ERROR;
        }
        if (userId == USER_REPAIR_MODE && !LockPatternUtils.isRepairModeActive(mContext)) {
            Slog.e(TAG, "Repair mode is not active on the device.");
            return VerifyCredentialResponse.ERROR;
        }
        Slogf.i(TAG, "Verifying lockscreen credential for user %d", userId);

        final AuthenticationResult authResult;
        VerifyCredentialResponse response;

        synchronized (mSpManager) {
            if (userId == USER_FRP) {
                return mSpManager.verifyFrpCredential(getGateKeeperService(), credential,
                        progressCallback);
            if (isSpecialUserId(userId)) {
                return mSpManager.verifySpecialUserCredential(userId, getGateKeeperService(),
                        credential, progressCallback);
            }

            long protectorId = getCurrentLskfBasedProtectorId(userId);
+4 −3
Original line number Diff line number Diff line
@@ -19,7 +19,7 @@ package com.android.server.locksettings;
import static android.content.Context.USER_SERVICE;

import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
import static com.android.internal.widget.LockPatternUtils.USER_FRP;
import static com.android.internal.widget.LockPatternUtils.isSpecialUserId;

import android.annotation.Nullable;
import android.app.admin.DevicePolicyManager;
@@ -536,7 +536,8 @@ class LockSettingsStorage {
    }

    public void setString(String key, String value, int userId) {
        Preconditions.checkArgument(userId != USER_FRP, "cannot store lock settings for FRP user");
        Preconditions.checkArgument(!isSpecialUserId(userId),
                "cannot store lock settings for special user: %d", userId);

        writeKeyValue(key, value, userId);
        if (ArrayUtils.contains(SETTINGS_TO_BACKUP, key)) {
@@ -561,7 +562,7 @@ class LockSettingsStorage {
    }

    public String getString(String key, String defaultValue, int userId) {
        if (userId == USER_FRP) {
        if (isSpecialUserId(userId)) {
            return null;
        }
        return readKeyValue(key, defaultValue, userId);
Loading