Merge "Use isCredentialSharedWithParent in LockSettingsService"
This commit is contained in:
committed by
Android (Google) Code Review
commit
f86b75c9f2
@@ -9648,6 +9648,7 @@ package android.os {
|
||||
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean hasUserRestrictionForUser(@NonNull String, @NonNull android.os.UserHandle);
|
||||
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public boolean isAdminUser();
|
||||
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean isCloneProfile();
|
||||
method public boolean isCredentialSharedWithParent();
|
||||
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public boolean isGuestUser();
|
||||
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.QUERY_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean isManagedProfile(int);
|
||||
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean isMediaSharedWithParent();
|
||||
|
||||
@@ -111,6 +111,7 @@ interface IUserManager {
|
||||
boolean isManagedProfile(int userId);
|
||||
boolean isCloneProfile(int userId);
|
||||
boolean isMediaSharedWithParent(int userId);
|
||||
boolean isCredentialSharedWithParent(int userId);
|
||||
boolean isDemoUser(int userId);
|
||||
boolean isPreCreated(int userId);
|
||||
UserInfo createProfileForUserEvenWhenDisallowedWithThrow(in String name, in String userType, int flags,
|
||||
|
||||
@@ -4757,6 +4757,28 @@ public class UserManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the user shares lock settings credential with its parent user
|
||||
*
|
||||
* This API only works for {@link UserManager#isProfile() profiles}
|
||||
* and will always return false for any other user type.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
@UserHandleAware(
|
||||
requiresAnyOfPermissionsIfNotCallerProfileGroup = {
|
||||
Manifest.permission.MANAGE_USERS,
|
||||
Manifest.permission.INTERACT_ACROSS_USERS})
|
||||
@SuppressAutoDoc
|
||||
public boolean isCredentialSharedWithParent() {
|
||||
try {
|
||||
return mService.isCredentialSharedWithParent(mUserId);
|
||||
} catch (RemoteException re) {
|
||||
throw re.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a user and all associated data.
|
||||
* @param userId the integer handle of the user.
|
||||
|
||||
@@ -34,6 +34,7 @@ import android.compat.annotation.UnsupportedAppUsage;
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
@@ -65,6 +66,7 @@ import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -194,6 +196,8 @@ public class LockPatternUtils {
|
||||
private final SparseLongArray mLockoutDeadlines = new SparseLongArray();
|
||||
private Boolean mHasSecureLockScreen;
|
||||
|
||||
private HashMap<UserHandle, UserManager> mUserManagerCache = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Use {@link TrustManager#isTrustUsuallyManaged(int)}.
|
||||
*
|
||||
@@ -265,6 +269,22 @@ public class LockPatternUtils {
|
||||
return mUserManager;
|
||||
}
|
||||
|
||||
private UserManager getUserManager(int userId) {
|
||||
UserHandle userHandle = UserHandle.of(userId);
|
||||
if (mUserManagerCache.containsKey(userHandle)) {
|
||||
return mUserManagerCache.get(userHandle);
|
||||
}
|
||||
|
||||
try {
|
||||
Context userContext = mContext.createPackageContextAsUser("system", 0, userHandle);
|
||||
UserManager userManager = userContext.getSystemService(UserManager.class);
|
||||
mUserManagerCache.put(userHandle, userManager);
|
||||
return userManager;
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
throw new RuntimeException("Failed to create context for user " + userHandle, e);
|
||||
}
|
||||
}
|
||||
|
||||
private TrustManager getTrustManager() {
|
||||
TrustManager trust = (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
|
||||
if (trust == null) {
|
||||
@@ -812,16 +832,17 @@ public class LockPatternUtils {
|
||||
|
||||
/**
|
||||
* Enables/disables the Separate Profile Challenge for this {@code userHandle}. This is a no-op
|
||||
* for user handles that do not belong to a managed profile.
|
||||
* for user handles that do not belong to a profile that shares credential with parent.
|
||||
* (managed profile and clone profile share lock credential with parent).
|
||||
*
|
||||
* @param userHandle Managed profile user id
|
||||
* @param enabled True if separate challenge is enabled
|
||||
* @param profilePassword Managed profile previous password. Null when {@code enabled} is
|
||||
* @param profilePassword Managed/Clone profile previous password. Null when {@code enabled} is
|
||||
* true
|
||||
*/
|
||||
public void setSeparateProfileChallengeEnabled(int userHandle, boolean enabled,
|
||||
LockscreenCredential profilePassword) {
|
||||
if (!isManagedProfile(userHandle)) {
|
||||
if (!isCredentialSharedWithParent(userHandle)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
@@ -837,7 +858,7 @@ public class LockPatternUtils {
|
||||
* Returns true if {@code userHandle} is a managed profile with separate challenge.
|
||||
*/
|
||||
public boolean isSeparateProfileChallengeEnabled(int userHandle) {
|
||||
return isManagedProfile(userHandle) && hasSeparateChallenge(userHandle);
|
||||
return isCredentialSharedWithParent(userHandle) && hasSeparateChallenge(userHandle);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -862,6 +883,10 @@ public class LockPatternUtils {
|
||||
return info != null && info.isManagedProfile();
|
||||
}
|
||||
|
||||
private boolean isCredentialSharedWithParent(int userHandle) {
|
||||
return getUserManager(userHandle).isCredentialSharedWithParent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserialize a pattern.
|
||||
* @param bytes The pattern serialized with {@link #patternToByteArray}
|
||||
|
||||
@@ -171,6 +171,7 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
@@ -236,7 +237,7 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
private final Random mRandom;
|
||||
|
||||
private final NotificationManager mNotificationManager;
|
||||
private final UserManager mUserManager;
|
||||
protected final UserManager mUserManager;
|
||||
private final IStorageManager mStorageManager;
|
||||
private final IActivityManager mActivityManager;
|
||||
private final SyntheticPasswordManager mSpManager;
|
||||
@@ -268,6 +269,8 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
private static final int[] SYSTEM_CREDENTIAL_UIDS = {
|
||||
Process.VPN_UID, Process.ROOT_UID, Process.SYSTEM_UID};
|
||||
|
||||
private HashMap<UserHandle, UserManager> mUserManagerCache = new HashMap<>();
|
||||
|
||||
// This class manages life cycle events for encrypted users on File Based Encryption (FBE)
|
||||
// devices. The most basic of these is to show/hide notifications about missing features until
|
||||
// the user unlocks the account and credential-encrypted storage is available.
|
||||
@@ -357,35 +360,36 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
}
|
||||
|
||||
/**
|
||||
* Tie managed profile to primary profile if it is in unified mode and not tied before.
|
||||
* Tie profile to primary profile if it is in unified mode and not tied before.
|
||||
* Only for profiles which share credential with parent. (e.g. managed and clone profiles)
|
||||
*
|
||||
* @param managedUserId Managed profile user Id
|
||||
* @param managedUserPassword Managed profile original password (when it has separated lock).
|
||||
* @param profileUserId profile user Id
|
||||
* @param profileUserPassword profile original password (when it has separated lock).
|
||||
*/
|
||||
public void tieManagedProfileLockIfNecessary(int managedUserId,
|
||||
LockscreenCredential managedUserPassword) {
|
||||
if (DEBUG) Slog.v(TAG, "Check child profile lock for user: " + managedUserId);
|
||||
// Only for managed profile
|
||||
if (!mUserManager.getUserInfo(managedUserId).isManagedProfile()) {
|
||||
public void tieProfileLockIfNecessary(int profileUserId,
|
||||
LockscreenCredential profileUserPassword) {
|
||||
if (DEBUG) Slog.v(TAG, "Check child profile lock for user: " + profileUserId);
|
||||
// Only for profiles that shares credential with parent
|
||||
if (!isCredentialSharedWithParent(profileUserId)) {
|
||||
return;
|
||||
}
|
||||
// Do not tie managed profile when work challenge is enabled
|
||||
if (getSeparateProfileChallengeEnabledInternal(managedUserId)) {
|
||||
// Do not tie profile when work challenge is enabled
|
||||
if (getSeparateProfileChallengeEnabledInternal(profileUserId)) {
|
||||
return;
|
||||
}
|
||||
// Do not tie managed profile to parent when it's done already
|
||||
if (mStorage.hasChildProfileLock(managedUserId)) {
|
||||
// Do not tie profile to parent when it's done already
|
||||
if (mStorage.hasChildProfileLock(profileUserId)) {
|
||||
return;
|
||||
}
|
||||
// If parent does not have a screen lock, simply clear credential from the managed profile,
|
||||
// If parent does not have a screen lock, simply clear credential from the profile,
|
||||
// to maintain the invariant that unified profile should always have the same secure state
|
||||
// as its parent.
|
||||
final int parentId = mUserManager.getProfileParent(managedUserId).id;
|
||||
if (!isUserSecure(parentId) && !managedUserPassword.isNone()) {
|
||||
final int parentId = mUserManager.getProfileParent(profileUserId).id;
|
||||
if (!isUserSecure(parentId) && !profileUserPassword.isNone()) {
|
||||
if (DEBUG) Slog.v(TAG, "Parent does not have a screen lock but profile has one");
|
||||
|
||||
setLockCredentialInternal(LockscreenCredential.createNone(), managedUserPassword,
|
||||
managedUserId, /* isLockTiedToParent= */ true);
|
||||
setLockCredentialInternal(LockscreenCredential.createNone(), profileUserPassword,
|
||||
profileUserId, /* isLockTiedToParent= */ true);
|
||||
return;
|
||||
}
|
||||
// Do not tie when the parent has no SID (but does have a screen lock).
|
||||
@@ -399,12 +403,12 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
Slog.e(TAG, "Failed to talk to GateKeeper service", e);
|
||||
return;
|
||||
}
|
||||
if (DEBUG) Slog.v(TAG, "Tie managed profile to parent now!");
|
||||
if (DEBUG) Slog.v(TAG, "Tie profile to parent now!");
|
||||
try (LockscreenCredential unifiedProfilePassword = generateRandomProfilePassword()) {
|
||||
setLockCredentialInternal(unifiedProfilePassword, managedUserPassword, managedUserId,
|
||||
setLockCredentialInternal(unifiedProfilePassword, profileUserPassword, profileUserId,
|
||||
/* isLockTiedToParent= */ true);
|
||||
tieProfileLockToParent(managedUserId, unifiedProfilePassword);
|
||||
mManagedProfilePasswordCache.storePassword(managedUserId, unifiedProfilePassword);
|
||||
tieProfileLockToParent(profileUserId, unifiedProfilePassword);
|
||||
mManagedProfilePasswordCache.storePassword(profileUserId, unifiedProfilePassword);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -766,9 +770,9 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
private void ensureProfileKeystoreUnlocked(int userId) {
|
||||
final KeyStore ks = KeyStore.getInstance();
|
||||
if (ks.state(userId) == KeyStore.State.LOCKED
|
||||
&& mUserManager.getUserInfo(userId).isManagedProfile()
|
||||
&& isCredentialSharedWithParent(userId)
|
||||
&& hasUnifiedChallenge(userId)) {
|
||||
Slog.i(TAG, "Managed profile got unlocked, will unlock its keystore");
|
||||
Slog.i(TAG, "Profile got unlocked, will unlock its keystore");
|
||||
// If boot took too long and the password in vold got expired, parent keystore will
|
||||
// be still locked, we ignore this case since the user will be prompted to unlock
|
||||
// the device after boot.
|
||||
@@ -787,8 +791,8 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
// Hide notification first, as tie managed profile lock takes time
|
||||
hideEncryptionNotification(new UserHandle(userId));
|
||||
|
||||
if (mUserManager.getUserInfo(userId).isManagedProfile()) {
|
||||
tieManagedProfileLockIfNecessary(userId, LockscreenCredential.createNone());
|
||||
if (isCredentialSharedWithParent(userId)) {
|
||||
tieProfileLockIfNecessary(userId, LockscreenCredential.createNone());
|
||||
}
|
||||
|
||||
// If the user doesn't have a credential, try and derive their secret for the
|
||||
@@ -1054,7 +1058,8 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
final int userCount = users.size();
|
||||
for (int i = 0; i < userCount; i++) {
|
||||
UserInfo user = users.get(i);
|
||||
if (user.isManagedProfile() && !getSeparateProfileChallengeEnabledInternal(user.id)) {
|
||||
if (isCredentialSharedWithParent(user.id)
|
||||
&& !getSeparateProfileChallengeEnabledInternal(user.id)) {
|
||||
success &= SyntheticPasswordCrypto.migrateLockSettingsKey(
|
||||
PROFILE_KEY_NAME_ENCRYPT + user.id);
|
||||
success &= SyntheticPasswordCrypto.migrateLockSettingsKey(
|
||||
@@ -1178,24 +1183,24 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
|
||||
@Override
|
||||
public void setSeparateProfileChallengeEnabled(int userId, boolean enabled,
|
||||
LockscreenCredential managedUserPassword) {
|
||||
LockscreenCredential profileUserPassword) {
|
||||
checkWritePermission(userId);
|
||||
if (!mHasSecureLockScreen
|
||||
&& managedUserPassword != null
|
||||
&& managedUserPassword.getType() != CREDENTIAL_TYPE_NONE) {
|
||||
&& profileUserPassword != null
|
||||
&& profileUserPassword.getType() != CREDENTIAL_TYPE_NONE) {
|
||||
throw new UnsupportedOperationException(
|
||||
"This operation requires secure lock screen feature.");
|
||||
}
|
||||
synchronized (mSeparateChallengeLock) {
|
||||
setSeparateProfileChallengeEnabledLocked(userId, enabled, managedUserPassword != null
|
||||
? managedUserPassword : LockscreenCredential.createNone());
|
||||
setSeparateProfileChallengeEnabledLocked(userId, enabled, profileUserPassword != null
|
||||
? profileUserPassword : LockscreenCredential.createNone());
|
||||
}
|
||||
notifySeparateProfileChallengeChanged(userId);
|
||||
}
|
||||
|
||||
@GuardedBy("mSeparateChallengeLock")
|
||||
private void setSeparateProfileChallengeEnabledLocked(@UserIdInt int userId,
|
||||
boolean enabled, LockscreenCredential managedUserPassword) {
|
||||
boolean enabled, LockscreenCredential profileUserPassword) {
|
||||
final boolean old = getBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, false, userId);
|
||||
setBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, enabled, userId);
|
||||
try {
|
||||
@@ -1203,7 +1208,7 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
mStorage.removeChildProfileLock(userId);
|
||||
removeKeystoreProfileKey(userId);
|
||||
} else {
|
||||
tieManagedProfileLockIfNecessary(userId, managedUserPassword);
|
||||
tieProfileLockIfNecessary(userId, profileUserPassword);
|
||||
}
|
||||
} catch (IllegalStateException e) {
|
||||
setBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, old, userId);
|
||||
@@ -1399,8 +1404,8 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlock the user (both storage and user state) and its associated managed profiles
|
||||
* synchronously.
|
||||
* Unlock the user (both storage and user state) and its associated profiles
|
||||
* that share lock credential (e.g. managed and clone profiles) synchronously.
|
||||
*
|
||||
* <em>Be very careful about the risk of deadlock here: ActivityManager.unlockUser()
|
||||
* can end up calling into other system services to process user unlock request (via
|
||||
@@ -1442,7 +1447,7 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
|
||||
if (mUserManager.getUserInfo(userId).isManagedProfile()) {
|
||||
if (isCredentialSharedWithParent(userId)) {
|
||||
if (!hasUnifiedChallenge(userId)) {
|
||||
mBiometricDeferredQueue.processPendingLockoutResets();
|
||||
}
|
||||
@@ -1451,11 +1456,11 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
|
||||
for (UserInfo profile : mUserManager.getProfiles(userId)) {
|
||||
if (profile.id == userId) continue;
|
||||
if (!profile.isManagedProfile()) continue;
|
||||
if (!isCredentialSharedWithParent(profile.id)) continue;
|
||||
|
||||
if (hasUnifiedChallenge(profile.id)) {
|
||||
if (mUserManager.isUserRunning(profile.id)) {
|
||||
// Unlock managed profile with unified lock
|
||||
// Unlock profile with unified lock
|
||||
unlockChildProfile(profile.id, false /* ignoreUserNotAuthenticated */);
|
||||
} else {
|
||||
try {
|
||||
@@ -1488,7 +1493,7 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
}
|
||||
|
||||
private Map<Integer, LockscreenCredential> getDecryptedPasswordsForAllTiedProfiles(int userId) {
|
||||
if (mUserManager.getUserInfo(userId).isManagedProfile()) {
|
||||
if (isCredentialSharedWithParent(userId)) {
|
||||
return null;
|
||||
}
|
||||
Map<Integer, LockscreenCredential> result = new ArrayMap<>();
|
||||
@@ -1496,21 +1501,21 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
final int size = profiles.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
final UserInfo profile = profiles.get(i);
|
||||
if (!profile.isManagedProfile()) {
|
||||
if (!isCredentialSharedWithParent(profile.id)) {
|
||||
continue;
|
||||
}
|
||||
final int managedUserId = profile.id;
|
||||
if (getSeparateProfileChallengeEnabledInternal(managedUserId)) {
|
||||
final int profileUserId = profile.id;
|
||||
if (getSeparateProfileChallengeEnabledInternal(profileUserId)) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
result.put(managedUserId, getDecryptedPasswordForTiedProfile(managedUserId));
|
||||
result.put(profileUserId, getDecryptedPasswordForTiedProfile(profileUserId));
|
||||
} catch (KeyStoreException | UnrecoverableKeyException | NoSuchAlgorithmException
|
||||
| NoSuchPaddingException | InvalidKeyException
|
||||
| InvalidAlgorithmParameterException | IllegalBlockSizeException
|
||||
| BadPaddingException | CertificateException | IOException e) {
|
||||
Slog.e(TAG, "getDecryptedPasswordsForAllTiedProfiles failed for user " +
|
||||
managedUserId, e);
|
||||
profileUserId, e);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@@ -1526,11 +1531,12 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
*
|
||||
* Strictly this is a recursive function, since setLockCredentialInternal ends up calling this
|
||||
* method again on profiles. However the recursion is guaranteed to terminate as this method
|
||||
* terminates when the user is a managed profile.
|
||||
* terminates when the user is a profile that shares lock credentials with parent.
|
||||
* (e.g. managed and clone profile).
|
||||
*/
|
||||
private void synchronizeUnifiedWorkChallengeForProfiles(int userId,
|
||||
Map<Integer, LockscreenCredential> profilePasswordMap) {
|
||||
if (mUserManager.getUserInfo(userId).isManagedProfile()) {
|
||||
if (isCredentialSharedWithParent(userId)) {
|
||||
return;
|
||||
}
|
||||
final boolean isSecure = isUserSecure(userId);
|
||||
@@ -1538,25 +1544,25 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
final int size = profiles.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
final UserInfo profile = profiles.get(i);
|
||||
if (profile.isManagedProfile()) {
|
||||
final int managedUserId = profile.id;
|
||||
if (getSeparateProfileChallengeEnabledInternal(managedUserId)) {
|
||||
final int profileUserId = profile.id;
|
||||
if (isCredentialSharedWithParent(profileUserId)) {
|
||||
if (getSeparateProfileChallengeEnabledInternal(profileUserId)) {
|
||||
continue;
|
||||
}
|
||||
if (isSecure) {
|
||||
tieManagedProfileLockIfNecessary(managedUserId,
|
||||
tieProfileLockIfNecessary(profileUserId,
|
||||
LockscreenCredential.createNone());
|
||||
} else {
|
||||
// We use cached work profile password computed before clearing the parent's
|
||||
// credential, otherwise they get lost
|
||||
if (profilePasswordMap != null
|
||||
&& profilePasswordMap.containsKey(managedUserId)) {
|
||||
&& profilePasswordMap.containsKey(profileUserId)) {
|
||||
setLockCredentialInternal(LockscreenCredential.createNone(),
|
||||
profilePasswordMap.get(managedUserId),
|
||||
managedUserId,
|
||||
profilePasswordMap.get(profileUserId),
|
||||
profileUserId,
|
||||
/* isLockTiedToParent= */ true);
|
||||
mStorage.removeChildProfileLock(managedUserId);
|
||||
removeKeystoreProfileKey(managedUserId);
|
||||
mStorage.removeChildProfileLock(profileUserId);
|
||||
removeKeystoreProfileKey(profileUserId);
|
||||
} else {
|
||||
Slog.wtf(TAG, "Attempt to clear tied challenge, but no password supplied.");
|
||||
}
|
||||
@@ -1565,13 +1571,13 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isManagedProfileWithUnifiedLock(int userId) {
|
||||
return mUserManager.getUserInfo(userId).isManagedProfile()
|
||||
private boolean isProfileWithUnifiedLock(int userId) {
|
||||
return isCredentialSharedWithParent(userId)
|
||||
&& !getSeparateProfileChallengeEnabledInternal(userId);
|
||||
}
|
||||
|
||||
private boolean isManagedProfileWithSeparatedLock(int userId) {
|
||||
return mUserManager.getUserInfo(userId).isManagedProfile()
|
||||
private boolean isProfileWithSeparatedLock(int userId) {
|
||||
return isCredentialSharedWithParent(userId)
|
||||
&& getSeparateProfileChallengeEnabledInternal(userId);
|
||||
}
|
||||
|
||||
@@ -1588,7 +1594,7 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
// A profile with a unified lock screen stores a randomly generated credential, so skip it.
|
||||
// Its parent will send credentials for the profile, as it stores the unified lock
|
||||
// credential.
|
||||
if (isManagedProfileWithUnifiedLock(userId)) {
|
||||
if (isProfileWithUnifiedLock(userId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1632,7 +1638,7 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
for (UserInfo profile : mUserManager.getProfiles(userId)) {
|
||||
if (profile.id == userId
|
||||
|| (profile.profileGroupId == userId
|
||||
&& isManagedProfileWithUnifiedLock(profile.id))) {
|
||||
&& isProfileWithUnifiedLock(profile.id))) {
|
||||
profiles.add(profile.id);
|
||||
}
|
||||
}
|
||||
@@ -1671,7 +1677,7 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
// accept only the parent user credential on its public API interfaces, swap it
|
||||
// with the profile's random credential at that API boundary (i.e. here) and make
|
||||
// sure LSS internally does not special case profile with unififed challenge: b/80170828
|
||||
if (!savedCredential.isNone() && isManagedProfileWithUnifiedLock(userId)) {
|
||||
if (!savedCredential.isNone() && isProfileWithUnifiedLock(userId)) {
|
||||
// Verify the parent credential again, to make sure we have a fresh enough
|
||||
// auth token such that getDecryptedPasswordForTiedProfile() inside
|
||||
// setLockCredentialInternal() can function correctly.
|
||||
@@ -1689,7 +1695,7 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
setSeparateProfileChallengeEnabledLocked(userId, true, /* unused */ null);
|
||||
notifyPasswordChanged(userId);
|
||||
}
|
||||
if (mUserManager.getUserInfo(userId).isManagedProfile()) {
|
||||
if (isCredentialSharedWithParent(userId)) {
|
||||
// Make sure the profile doesn't get locked straight after setting work challenge.
|
||||
setDeviceUnlockedForUser(userId);
|
||||
}
|
||||
@@ -1703,7 +1709,8 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param savedCredential if the user is a managed profile with unified challenge and
|
||||
* @param savedCredential if the user is a profile with
|
||||
* {@link UserManager#isCredentialSharedWithParent()} with unified challenge and
|
||||
* savedCredential is empty, LSS will try to re-derive the profile password internally.
|
||||
* TODO (b/80170828): Fix this so profile password is always passed in.
|
||||
* @param isLockTiedToParent is {@code true} if {@code userId} is a profile and its new
|
||||
@@ -1737,8 +1744,8 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
}
|
||||
|
||||
CredentialHash currentHandle = mStorage.readCredentialHash(userId);
|
||||
if (isManagedProfileWithUnifiedLock(userId)) {
|
||||
// get credential from keystore when managed profile has unified lock
|
||||
if (isProfileWithUnifiedLock(userId)) {
|
||||
// get credential from keystore when managed/clone profile has unified lock
|
||||
if (savedCredential.isNone()) {
|
||||
try {
|
||||
//TODO: remove as part of b/80170828
|
||||
@@ -1880,6 +1887,26 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
return value != 0;
|
||||
}
|
||||
|
||||
private UserManager getUserManagerFromCache(int userId) {
|
||||
UserHandle userHandle = UserHandle.of(userId);
|
||||
if (mUserManagerCache.containsKey(userHandle)) {
|
||||
return mUserManagerCache.get(userHandle);
|
||||
}
|
||||
|
||||
try {
|
||||
Context userContext = mContext.createPackageContextAsUser("system", 0, userHandle);
|
||||
UserManager userManager = userContext.getSystemService(UserManager.class);
|
||||
mUserManagerCache.put(userHandle, userManager);
|
||||
return userManager;
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
throw new RuntimeException("Failed to create context for user " + userHandle, e);
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean isCredentialSharedWithParent(int userId) {
|
||||
return getUserManagerFromCache(userId).isCredentialSharedWithParent();
|
||||
}
|
||||
|
||||
private VerifyCredentialResponse convertResponse(GateKeeperResponse gateKeeperResponse) {
|
||||
return VerifyCredentialResponse.fromGateKeeperResponse(gateKeeperResponse);
|
||||
}
|
||||
@@ -2150,23 +2177,17 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
public void resetKeyStore(int userId) {
|
||||
checkWritePermission(userId);
|
||||
if (DEBUG) Slog.v(TAG, "Reset keystore for user: " + userId);
|
||||
int managedUserId = -1;
|
||||
LockscreenCredential managedUserDecryptedPassword = null;
|
||||
List<Integer> profileUserIds = new ArrayList<>();
|
||||
List<LockscreenCredential> profileUserDecryptedPasswords = new ArrayList<>();
|
||||
final List<UserInfo> profiles = mUserManager.getProfiles(userId);
|
||||
for (UserInfo pi : profiles) {
|
||||
// Unlock managed profile with unified lock
|
||||
if (pi.isManagedProfile()
|
||||
// Unlock profile which shares credential with parent with unified lock
|
||||
if (isCredentialSharedWithParent(pi.id)
|
||||
&& !getSeparateProfileChallengeEnabledInternal(pi.id)
|
||||
&& mStorage.hasChildProfileLock(pi.id)) {
|
||||
try {
|
||||
if (managedUserId == -1) {
|
||||
managedUserDecryptedPassword = getDecryptedPasswordForTiedProfile(pi.id);
|
||||
managedUserId = pi.id;
|
||||
} else {
|
||||
// Should not happen
|
||||
Slog.e(TAG, "More than one managed profile, uid1:" + managedUserId
|
||||
+ ", uid2:" + pi.id);
|
||||
}
|
||||
profileUserDecryptedPasswords.add(getDecryptedPasswordForTiedProfile(pi.id));
|
||||
profileUserIds.add(pi.id);
|
||||
} catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
|
||||
| NoSuchAlgorithmException | NoSuchPaddingException
|
||||
| InvalidAlgorithmParameterException | IllegalBlockSizeException
|
||||
@@ -2188,14 +2209,18 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
KeyProperties.NAMESPACE_WIFI);
|
||||
}
|
||||
} finally {
|
||||
if (managedUserId != -1 && managedUserDecryptedPassword != null) {
|
||||
if (DEBUG) Slog.v(TAG, "Restore tied profile lock");
|
||||
tieProfileLockToParent(managedUserId, managedUserDecryptedPassword);
|
||||
for (int i = 0; i < profileUserIds.size(); ++i) {
|
||||
int piUserId = profileUserIds.get(i);
|
||||
LockscreenCredential piUserDecryptedPassword = profileUserDecryptedPasswords.get(i);
|
||||
if (piUserId != -1 && piUserDecryptedPassword != null) {
|
||||
if (DEBUG) Slog.v(TAG, "Restore tied profile lock");
|
||||
tieProfileLockToParent(piUserId, piUserDecryptedPassword);
|
||||
}
|
||||
if (piUserDecryptedPassword != null) {
|
||||
piUserDecryptedPassword.zeroize();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (managedUserDecryptedPassword != null) {
|
||||
managedUserDecryptedPassword.zeroize();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -2317,8 +2342,9 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
public VerifyCredentialResponse verifyTiedProfileChallenge(LockscreenCredential credential,
|
||||
int userId, @LockPatternUtils.VerifyFlag int flags) {
|
||||
checkPasswordReadPermission();
|
||||
if (!isManagedProfileWithUnifiedLock(userId)) {
|
||||
throw new IllegalArgumentException("User id must be managed profile with unified lock");
|
||||
if (!isProfileWithUnifiedLock(userId)) {
|
||||
throw new IllegalArgumentException(
|
||||
"User id must be managed/clone profile with unified lock");
|
||||
}
|
||||
final int parentProfileId = mUserManager.getProfileParent(userId).id;
|
||||
// Unlock parent by using parent's challenge
|
||||
@@ -2395,7 +2421,7 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
Slog.i(TAG, "Unlocking user " + userId);
|
||||
unlockUser(userId, secretFromCredential(credential));
|
||||
|
||||
if (isManagedProfileWithSeparatedLock(userId)) {
|
||||
if (isProfileWithSeparatedLock(userId)) {
|
||||
setDeviceUnlockedForUser(userId);
|
||||
}
|
||||
if (shouldReEnroll) {
|
||||
@@ -2548,7 +2574,7 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
mManagedProfilePasswordCache.removePassword(userId);
|
||||
|
||||
gateKeeperClearSecureUserId(userId);
|
||||
if (unknownUser || mUserManager.getUserInfo(userId).isManagedProfile()) {
|
||||
if (unknownUser || isCredentialSharedWithParent(userId)) {
|
||||
removeKeystoreProfileKey(userId);
|
||||
}
|
||||
// Clean up storage last, this is to ensure that cleanupDataForReusedUserIdIfNecessary()
|
||||
@@ -3058,7 +3084,7 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
}
|
||||
activateEscrowTokens(authToken, userId);
|
||||
|
||||
if (isManagedProfileWithSeparatedLock(userId)) {
|
||||
if (isProfileWithSeparatedLock(userId)) {
|
||||
setDeviceUnlockedForUser(userId);
|
||||
}
|
||||
mStrongAuth.reportSuccessfulStrongAuthUnlock(userId);
|
||||
@@ -3215,7 +3241,7 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param savedCredential if the user is a managed profile with unified challenge and
|
||||
* @param savedCredential if the user is a profile with unified challenge and
|
||||
* savedCredential is empty, LSS will try to re-derive the profile password internally.
|
||||
* TODO (b/80170828): Fix this so profile password is always passed in.
|
||||
*/
|
||||
@@ -3223,8 +3249,8 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
private boolean spBasedSetLockCredentialInternalLocked(LockscreenCredential credential,
|
||||
LockscreenCredential savedCredential, int userId, boolean isLockTiedToParent) {
|
||||
if (DEBUG) Slog.d(TAG, "spBasedSetLockCredentialInternalLocked: user=" + userId);
|
||||
if (savedCredential.isNone() && isManagedProfileWithUnifiedLock(userId)) {
|
||||
// get credential from keystore when managed profile has unified lock
|
||||
if (savedCredential.isNone() && isProfileWithUnifiedLock(userId)) {
|
||||
// get credential from keystore when profile has unified lock
|
||||
try {
|
||||
//TODO: remove as part of b/80170828
|
||||
savedCredential = getDecryptedPasswordForTiedProfile(userId);
|
||||
@@ -3268,13 +3294,14 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
* Returns a fixed pseudorandom byte string derived from the user's synthetic password.
|
||||
* This is used to salt the password history hash to protect the hash against offline
|
||||
* bruteforcing, since rederiving this value requires a successful authentication.
|
||||
* If user is a managed profile with unified challenge, currentCredential is ignored.
|
||||
* If user is a profile with {@link UserManager#isCredentialSharedWithParent()} true and with
|
||||
* unified challenge, currentCredential is ignored.
|
||||
*/
|
||||
@Override
|
||||
public byte[] getHashFactor(LockscreenCredential currentCredential, int userId) {
|
||||
checkPasswordReadPermission();
|
||||
try {
|
||||
if (isManagedProfileWithUnifiedLock(userId)) {
|
||||
if (isProfileWithUnifiedLock(userId)) {
|
||||
try {
|
||||
currentCredential = getDecryptedPasswordForTiedProfile(userId);
|
||||
} catch (Exception e) {
|
||||
@@ -3744,10 +3771,11 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
public PasswordMetrics getUserPasswordMetrics(int userHandle) {
|
||||
final long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
if (isManagedProfileWithUnifiedLock(userHandle)) {
|
||||
// A managed profile with unified challenge is supposed to be protected by the
|
||||
// parent lockscreen, so asking for its password metrics is not really useful,
|
||||
// as this method would just return the metrics of the random profile password
|
||||
if (isProfileWithUnifiedLock(userHandle)) {
|
||||
// A managed/clone profile with unified challenge is supposed to be protected by
|
||||
// the parent lockscreen, so asking for its password metrics is not really
|
||||
// useful, as this method would just return the metrics of the random profile
|
||||
// password
|
||||
Slog.w(TAG, "Querying password metrics for unified challenge profile: "
|
||||
+ userHandle);
|
||||
}
|
||||
|
||||
@@ -1555,6 +1555,17 @@ public class UserManagerService extends IUserManager.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCredentialSharedWithParent(@UserIdInt int userId) {
|
||||
checkManageOrInteractPermissionIfCallerInOtherProfileGroup(userId,
|
||||
"isCredentialSharedWithParent");
|
||||
synchronized (mUsersLock) {
|
||||
UserTypeDetails userTypeDetails = getUserTypeDetailsNoChecks(userId);
|
||||
return userTypeDetails != null && userTypeDetails.isProfile()
|
||||
&& userTypeDetails.isCredentialSharedWithParent();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUserUnlockingOrUnlocked(@UserIdInt int userId) {
|
||||
checkManageOrInteractPermissionIfCallerInOtherProfileGroup(userId,
|
||||
|
||||
@@ -156,6 +156,13 @@ public final class UserTypeDetails {
|
||||
*/
|
||||
private final boolean mIsMediaSharedWithParent;
|
||||
|
||||
/**
|
||||
* Denotes if the user shares encryption credentials with its parent user.
|
||||
*
|
||||
* <p> Default value is false
|
||||
*/
|
||||
private final boolean mIsCredentialSharedWithParent;
|
||||
|
||||
private UserTypeDetails(@NonNull String name, boolean enabled, int maxAllowed,
|
||||
@UserInfoFlag int baseType, @UserInfoFlag int defaultUserInfoPropertyFlags, int label,
|
||||
int maxAllowedPerParent,
|
||||
@@ -166,7 +173,8 @@ public final class UserTypeDetails {
|
||||
@Nullable Bundle defaultSystemSettings,
|
||||
@Nullable Bundle defaultSecureSettings,
|
||||
@Nullable List<DefaultCrossProfileIntentFilter> defaultCrossProfileIntentFilters,
|
||||
boolean isMediaSharedWithParent) {
|
||||
boolean isMediaSharedWithParent,
|
||||
boolean isCredentialSharedWithParent) {
|
||||
this.mName = name;
|
||||
this.mEnabled = enabled;
|
||||
this.mMaxAllowed = maxAllowed;
|
||||
@@ -186,6 +194,7 @@ public final class UserTypeDetails {
|
||||
this.mBadgeColors = badgeColors;
|
||||
this.mDarkThemeBadgeColors = darkThemeBadgeColors;
|
||||
this.mIsMediaSharedWithParent = isMediaSharedWithParent;
|
||||
this.mIsCredentialSharedWithParent = isCredentialSharedWithParent;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -310,6 +319,14 @@ public final class UserTypeDetails {
|
||||
return mIsMediaSharedWithParent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the user has shared encryption credential with parent user or
|
||||
* false otherwise.
|
||||
*/
|
||||
public boolean isCredentialSharedWithParent() {
|
||||
return mIsCredentialSharedWithParent;
|
||||
}
|
||||
|
||||
/** Returns a {@link Bundle} representing the default user restrictions. */
|
||||
@NonNull Bundle getDefaultRestrictions() {
|
||||
return BundleUtils.clone(mDefaultRestrictions);
|
||||
@@ -402,6 +419,7 @@ public final class UserTypeDetails {
|
||||
private @DrawableRes int mBadgePlain = Resources.ID_NULL;
|
||||
private @DrawableRes int mBadgeNoBackground = Resources.ID_NULL;
|
||||
private boolean mIsMediaSharedWithParent = false;
|
||||
private boolean mIsCredentialSharedWithParent = false;
|
||||
|
||||
public Builder setName(String name) {
|
||||
mName = name;
|
||||
@@ -501,6 +519,15 @@ public final class UserTypeDetails {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets shared media property for the user.
|
||||
* @param isCredentialSharedWithParent the value to be set, true or false
|
||||
*/
|
||||
public Builder setIsCredentialSharedWithParent(boolean isCredentialSharedWithParent) {
|
||||
mIsCredentialSharedWithParent = isCredentialSharedWithParent;
|
||||
return this;
|
||||
}
|
||||
|
||||
@UserInfoFlag int getBaseType() {
|
||||
return mBaseType;
|
||||
}
|
||||
@@ -543,7 +570,8 @@ public final class UserTypeDetails {
|
||||
mDefaultSystemSettings,
|
||||
mDefaultSecureSettings,
|
||||
mDefaultCrossProfileIntentFilters,
|
||||
mIsMediaSharedWithParent);
|
||||
mIsMediaSharedWithParent,
|
||||
mIsCredentialSharedWithParent);
|
||||
}
|
||||
|
||||
private boolean hasBadge() {
|
||||
|
||||
@@ -121,7 +121,8 @@ public final class UserTypeFactory {
|
||||
.setMaxAllowedPerParent(1)
|
||||
.setLabel(0)
|
||||
.setDefaultRestrictions(null)
|
||||
.setIsMediaSharedWithParent(true);
|
||||
.setIsMediaSharedWithParent(true)
|
||||
.setIsCredentialSharedWithParent(true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -152,7 +153,8 @@ public final class UserTypeFactory {
|
||||
com.android.internal.R.color.profile_badge_3_dark)
|
||||
.setDefaultRestrictions(getDefaultManagedProfileRestrictions())
|
||||
.setDefaultSecureSettings(getDefaultManagedProfileSecureSettings())
|
||||
.setDefaultCrossProfileIntentFilters(getDefaultManagedCrossProfileIntentFilter());
|
||||
.setDefaultCrossProfileIntentFilters(getDefaultManagedCrossProfileIntentFilter())
|
||||
.setIsCredentialSharedWithParent(true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -22,6 +22,7 @@ import android.app.IActivityManager;
|
||||
import android.app.admin.DeviceStateCache;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.hardware.authsecret.V1_0.IAuthSecret;
|
||||
import android.os.Handler;
|
||||
import android.os.Parcel;
|
||||
@@ -214,4 +215,10 @@ public class LockSettingsServiceTestable extends LockSettingsService {
|
||||
void setKeystorePassword(byte[] password, int userHandle) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isCredentialSharedWithParent(int userId) {
|
||||
UserInfo userInfo = mUserManager.getUserInfo(userId);
|
||||
return userInfo.isCloneProfile() || userInfo.isManagedProfile();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user