diff options
author | Andrew Scull <ascull@google.com> | 2017-01-13 15:28:36 +0000 |
---|---|---|
committer | The Android Automerger <android-build@android.com> | 2017-01-23 11:40:55 -0800 |
commit | 5494d68d465fe9326618f3ed88127f6401e0711a (patch) | |
tree | d0806622a9b82c9c3bc14d7db30c8795f73351bc | |
parent | c40c87f0cd0c4a8c5bfe6132ebe4bb13ead4052c (diff) | |
download | base-5494d68d465fe9326618f3ed88127f6401e0711a.tar.gz |
resolve merge conflicts of ad4aa1ce7d3d to nyc-mr1-dev
Change-Id: I97ef31536cd06495a08a3f94f81df2d1376186e0
(cherry picked from commit eb35ad9969a173ac4d6279a5e322e8176c2ae6d1)
5 files changed, 166 insertions, 104 deletions
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index a2f9bdd2370d..e23f142317ac 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -2016,7 +2016,8 @@ public class DevicePolicyManager { * Determine whether the current password the user has set is sufficient to meet the policy * requirements (e.g. quality, minimum length) that have been requested by the admins of this * user and its participating profiles. Restrictions on profiles that have a separate challenge - * are not taken into account. + * are not taken into account. If the user has a password, it must have been entered in order to + * perform this check. * <p> * The calling device admin must have requested * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call this method; if it has @@ -2029,6 +2030,7 @@ public class DevicePolicyManager { * @return Returns true if the password meets the current requirements, else false. * @throws SecurityException if the calling application does not own an active administrator * that uses {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} + * @throws IllegalStateException if the user has a password but has not entered it yet. */ public boolean isActivePasswordSufficient() { if (mService != null) { @@ -3541,6 +3543,19 @@ public class DevicePolicyManager { /** * @hide */ + public void reportPasswordChanged(int userId) { + if (mService != null) { + try { + mService.reportPasswordChanged(userId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + } + + /** + * @hide + */ public void reportFailedPasswordAttempt(int userHandle) { if (mService != null) { try { diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index f39cb5ae9fbd..90632a19a09b 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -119,6 +119,7 @@ interface IDevicePolicyManager { void setActivePasswordState(int quality, int length, int letters, int uppercase, int lowercase, int numbers, int symbols, int nonletter, int userHandle); + void reportPasswordChanged(int userId); void reportFailedPasswordAttempt(int userHandle); void reportSuccessfulPasswordAttempt(int userHandle); void reportFailedFingerprintAttempt(int userHandle); diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index 479b3b7a7a71..d49d433d665d 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -593,9 +593,6 @@ public class LockPatternUtils { setCredentialRequiredToDecrypt(false); } - getDevicePolicyManager().setActivePasswordState( - DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0, 0, 0, 0, 0, 0, userHandle); - onAfterChangingPassword(userHandle); } @@ -642,6 +639,7 @@ public class LockPatternUtils { + MIN_LOCK_PATTERN_SIZE + " dots long."); } + setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, userId); getLockSettings().setLockPattern(patternToString(pattern), savedPattern, userId); DevicePolicyManager dpm = getDevicePolicyManager(); @@ -658,9 +656,6 @@ public class LockPatternUtils { setBoolean(PATTERN_EVER_CHOSEN_KEY, true, userId); - setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, userId); - dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, - pattern.size(), 0, 0, 0, 0, 0, 0, userId); onAfterChangingPassword(userId); } catch (RemoteException re) { Log.e(TAG, "Couldn't save lock pattern " + re); @@ -863,9 +858,9 @@ public class LockPatternUtils { + "of length " + MIN_LOCK_PASSWORD_SIZE); } + final int computedQuality = computePasswordQuality(password); + setLong(PASSWORD_TYPE_KEY, Math.max(quality, computedQuality), userHandle); getLockSettings().setLockPassword(password, savedPassword, userHandle); - getLockSettings().setSeparateProfileChallengeEnabled(userHandle, true, null); - int computedQuality = computePasswordQuality(password); // Update the device encryption password. if (userHandle == UserHandle.USER_SYSTEM @@ -883,40 +878,6 @@ public class LockPatternUtils { } } - setLong(PASSWORD_TYPE_KEY, Math.max(quality, computedQuality), userHandle); - if (computedQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) { - int letters = 0; - int uppercase = 0; - int lowercase = 0; - int numbers = 0; - int symbols = 0; - int nonletter = 0; - for (int i = 0; i < password.length(); i++) { - char c = password.charAt(i); - if (c >= 'A' && c <= 'Z') { - letters++; - uppercase++; - } else if (c >= 'a' && c <= 'z') { - letters++; - lowercase++; - } else if (c >= '0' && c <= '9') { - numbers++; - nonletter++; - } else { - symbols++; - nonletter++; - } - } - dpm.setActivePasswordState(Math.max(quality, computedQuality), - password.length(), letters, uppercase, lowercase, - numbers, symbols, nonletter, userHandle); - } else { - // The password is not anything. - dpm.setActivePasswordState( - DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, - 0, 0, 0, 0, 0, 0, 0, userHandle); - } - // Add the password to the password history. We assume all // password hashes have the same length for simplicity of implementation. String passwordHistory = getString(PASSWORD_HISTORY_KEY, userHandle); diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java index a91e2053c01d..a3d8d85c576e 100644 --- a/services/core/java/com/android/server/LockSettingsService.java +++ b/services/core/java/com/android/server/LockSettingsService.java @@ -902,6 +902,7 @@ public class LockSettingsService extends ILockSettings.Stub { synchronized (mSeparateChallengeLock) { setLockPatternInternal(pattern, savedCredential, userId); setSeparateProfileChallengeEnabled(userId, true, null); + notifyPasswordChanged(userId); } } @@ -916,6 +917,7 @@ public class LockSettingsService extends ILockSettings.Stub { setKeystorePassword(null, userId); fixateNewestUserKeyAuth(userId); onUserLockChanged(userId); + notifyActivePasswordMetricsAvailable(null, userId); return; } @@ -965,6 +967,7 @@ public class LockSettingsService extends ILockSettings.Stub { synchronized (mSeparateChallengeLock) { setLockPasswordInternal(password, savedCredential, userId); setSeparateProfileChallengeEnabled(userId, true, null); + notifyPasswordChanged(userId); } } @@ -978,6 +981,7 @@ public class LockSettingsService extends ILockSettings.Stub { setKeystorePassword(null, userId); fixateNewestUserKeyAuth(userId); onUserLockChanged(userId); + notifyActivePasswordMetricsAvailable(null, userId); return; } @@ -1387,6 +1391,7 @@ public class LockSettingsService extends ILockSettings.Stub { // migrate credential to GateKeeper credentialUtil.setCredential(credential, null, userId); if (!hasChallenge) { + notifyActivePasswordMetricsAvailable(credential, userId); return VerifyCredentialResponse.OK; } // Fall through to get the auth token. Technically this should never happen, @@ -1426,6 +1431,7 @@ public class LockSettingsService extends ILockSettings.Stub { if (progressCallback != null) { progressCallback.onCredentialVerified(); } + notifyActivePasswordMetricsAvailable(credential, userId); unlockKeystore(credential, userId); Slog.i(TAG, "Unlocking user " + userId + @@ -1449,6 +1455,60 @@ public class LockSettingsService extends ILockSettings.Stub { return response; } + private void notifyActivePasswordMetricsAvailable(final String password, int userId) { + final int quality = mLockPatternUtils.getKeyguardStoredPasswordQuality(userId); + + // Asynchronous to avoid dead lock + mHandler.post(new Runnable() { + @Override + public void run() { + int length = 0; + int letters = 0; + int uppercase = 0; + int lowercase = 0; + int numbers = 0; + int symbols = 0; + int nonletter = 0; + if (password != null) { + length = password.length(); + for (int i = 0; i < length; i++) { + char c = password.charAt(i); + if (c >= 'A' && c <= 'Z') { + letters++; + uppercase++; + } else if (c >= 'a' && c <= 'z') { + letters++; + lowercase++; + } else if (c >= '0' && c <= '9') { + numbers++; + nonletter++; + } else { + symbols++; + nonletter++; + } + } + } + DevicePolicyManager dpm = (DevicePolicyManager) + mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); + dpm.setActivePasswordState(quality, length, letters, uppercase, lowercase, numbers, + symbols, nonletter, userId); + } + }); + } + + /** + * Call after {@link #notifyActivePasswordMetricsAvailable} so metrics are updated before + * reporting the password changed. + */ + private void notifyPasswordChanged(int userId) { + // Same handler as notifyActivePasswordMetricsAvailable to ensure correct ordering + mHandler.post(() -> { + DevicePolicyManager dpm = (DevicePolicyManager) + mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); + dpm.reportPasswordChanged(userId); + }); + } + @Override public boolean checkVoldPassword(int userId) throws RemoteException { if (!mFirstCallToVold) { diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 92aa1b98238f..fbb865bc64a9 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -2259,10 +2259,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { out.endTag(null, "failed-password-attempts"); } - if (policy.mActivePasswordQuality != 0 || policy.mActivePasswordLength != 0 + // Don't save metrics for FBE devices + if (!mInjector.storageManagerIsFileBasedEncryptionEnabled() + && (policy.mActivePasswordQuality != 0 || policy.mActivePasswordLength != 0 || policy.mActivePasswordUpperCase != 0 || policy.mActivePasswordLowerCase != 0 || policy.mActivePasswordLetters != 0 || policy.mActivePasswordNumeric != 0 - || policy.mActivePasswordSymbols != 0 || policy.mActivePasswordNonLetter != 0) { + || policy.mActivePasswordSymbols != 0 + || policy.mActivePasswordNonLetter != 0)) { out.startTag(null, "active-password"); out.attribute(null, "quality", Integer.toString(policy.mActivePasswordQuality)); out.attribute(null, "length", Integer.toString(policy.mActivePasswordLength)); @@ -2355,6 +2358,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { JournaledFile journal = makeJournaledFile(userHandle); FileInputStream stream = null; File file = journal.chooseForRead(); + boolean needsRewrite = false; try { stream = new FileInputStream(file); XmlPullParser parser = Xml.newPullParser(); @@ -2437,23 +2441,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } else if ("password-owner".equals(tag)) { policy.mPasswordOwner = Integer.parseInt( parser.getAttributeValue(null, "value")); - } else if ("active-password".equals(tag)) { - policy.mActivePasswordQuality = Integer.parseInt( - parser.getAttributeValue(null, "quality")); - policy.mActivePasswordLength = Integer.parseInt( - parser.getAttributeValue(null, "length")); - policy.mActivePasswordUpperCase = Integer.parseInt( - parser.getAttributeValue(null, "uppercase")); - policy.mActivePasswordLowerCase = Integer.parseInt( - parser.getAttributeValue(null, "lowercase")); - policy.mActivePasswordLetters = Integer.parseInt( - parser.getAttributeValue(null, "letters")); - policy.mActivePasswordNumeric = Integer.parseInt( - parser.getAttributeValue(null, "numeric")); - policy.mActivePasswordSymbols = Integer.parseInt( - parser.getAttributeValue(null, "symbols")); - policy.mActivePasswordNonLetter = Integer.parseInt( - parser.getAttributeValue(null, "nonletter")); } else if (TAG_ACCEPTED_CA_CERTIFICATES.equals(tag)) { policy.mAcceptedCaCertificates.add(parser.getAttributeValue(null, ATTR_NAME)); } else if (TAG_LOCK_TASK_COMPONENTS.equals(tag)) { @@ -2470,6 +2457,28 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { policy.mAdminBroadcastPending = Boolean.toString(true).equals(pending); } else if (TAG_INITIALIZATION_BUNDLE.equals(tag)) { policy.mInitBundle = PersistableBundle.restoreFromXml(parser); + } else if ("active-password".equals(tag)) { + if (mInjector.storageManagerIsFileBasedEncryptionEnabled()) { + // Remove this from FBE devices + needsRewrite = true; + } else { + policy.mActivePasswordQuality = Integer.parseInt( + parser.getAttributeValue(null, "quality")); + policy.mActivePasswordLength = Integer.parseInt( + parser.getAttributeValue(null, "length")); + policy.mActivePasswordUpperCase = Integer.parseInt( + parser.getAttributeValue(null, "uppercase")); + policy.mActivePasswordLowerCase = Integer.parseInt( + parser.getAttributeValue(null, "lowercase")); + policy.mActivePasswordLetters = Integer.parseInt( + parser.getAttributeValue(null, "letters")); + policy.mActivePasswordNumeric = Integer.parseInt( + parser.getAttributeValue(null, "numeric")); + policy.mActivePasswordSymbols = Integer.parseInt( + parser.getAttributeValue(null, "symbols")); + policy.mActivePasswordNonLetter = Integer.parseInt( + parser.getAttributeValue(null, "nonletter")); + } } else { Slog.w(LOG_TAG, "Unknown tag: " + tag); XmlUtils.skipCurrentTag(parser); @@ -2489,34 +2498,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // Ignore } + // Might need to upgrade the file by rewriting it + if (needsRewrite) { + saveSettingsLocked(userHandle); + } + // Generate a list of admins from the admin map policy.mAdminList.addAll(policy.mAdminMap.values()); - // Validate that what we stored for the password quality matches - // sufficiently what is currently set. Note that this is only - // a sanity check in case the two get out of sync; this should - // never normally happen. - final long identity = mInjector.binderClearCallingIdentity(); - try { - int actualPasswordQuality = mLockPatternUtils.getActivePasswordQuality(userHandle); - if (actualPasswordQuality < policy.mActivePasswordQuality) { - Slog.w(LOG_TAG, "Active password quality 0x" - + Integer.toHexString(policy.mActivePasswordQuality) - + " does not match actual quality 0x" - + Integer.toHexString(actualPasswordQuality)); - policy.mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; - policy.mActivePasswordLength = 0; - policy.mActivePasswordUpperCase = 0; - policy.mActivePasswordLowerCase = 0; - policy.mActivePasswordLetters = 0; - policy.mActivePasswordNumeric = 0; - policy.mActivePasswordSymbols = 0; - policy.mActivePasswordNonLetter = 0; - } - } finally { - mInjector.binderRestoreCallingIdentity(identity); - } - validatePasswordOwnerLocked(policy); updateMaximumTimeToLockLocked(userHandle); updateLockTaskPackagesLocked(policy.mLockTaskPackages, userHandle); @@ -3740,6 +3729,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private boolean isActivePasswordSufficientForUserLocked( DevicePolicyData policy, int userHandle, boolean parent) { + enforceUserUnlocked(userHandle, parent); + final int requiredPasswordQuality = getPasswordQuality(null, userHandle, parent); if (policy.mActivePasswordQuality < requiredPasswordQuality) { return false; @@ -4814,40 +4805,66 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return; } enforceFullCrossUsersPermission(userHandle); + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.BIND_DEVICE_ADMIN, null); + + // If the managed profile doesn't have a separate password, set the metrics to default + if (isManagedProfile(userHandle) && !isSeparateProfileChallengeEnabled(userHandle)) { + quality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; + length = 0; + letters = 0; + uppercase = 0; + lowercase = 0; + numbers = 0; + symbols = 0; + nonletter = 0; + } + + validateQualityConstant(quality); + DevicePolicyData policy = getUserData(userHandle); + synchronized (this) { + policy.mActivePasswordQuality = quality; + policy.mActivePasswordLength = length; + policy.mActivePasswordLetters = letters; + policy.mActivePasswordLowerCase = lowercase; + policy.mActivePasswordUpperCase = uppercase; + policy.mActivePasswordNumeric = numbers; + policy.mActivePasswordSymbols = symbols; + policy.mActivePasswordNonLetter = nonletter; + } + } + + @Override + public void reportPasswordChanged(int userId) { + if (!mHasFeature) { + return; + } + enforceFullCrossUsersPermission(userId); // Managed Profile password can only be changed when it has a separate challenge. - if (!isSeparateProfileChallengeEnabled(userHandle)) { - enforceNotManagedProfile(userHandle, "set the active password"); + if (!isSeparateProfileChallengeEnabled(userId)) { + enforceNotManagedProfile(userId, "set the active password"); } mContext.enforceCallingOrSelfPermission( android.Manifest.permission.BIND_DEVICE_ADMIN, null); - validateQualityConstant(quality); - DevicePolicyData policy = getUserData(userHandle); + DevicePolicyData policy = getUserData(userId); long ident = mInjector.binderClearCallingIdentity(); try { synchronized (this) { - policy.mActivePasswordQuality = quality; - policy.mActivePasswordLength = length; - policy.mActivePasswordLetters = letters; - policy.mActivePasswordLowerCase = lowercase; - policy.mActivePasswordUpperCase = uppercase; - policy.mActivePasswordNumeric = numbers; - policy.mActivePasswordSymbols = symbols; - policy.mActivePasswordNonLetter = nonletter; policy.mFailedPasswordAttempts = 0; - saveSettingsLocked(userHandle); - updatePasswordExpirationsLocked(userHandle); - setExpirationAlarmCheckLocked(mContext, userHandle, /* parent */ false); + saveSettingsLocked(userId); + updatePasswordExpirationsLocked(userId); + setExpirationAlarmCheckLocked(mContext, userId, /* parent */ false); // Send a broadcast to each profile using this password as its primary unlock. sendAdminCommandForLockscreenPoliciesLocked( DeviceAdminReceiver.ACTION_PASSWORD_CHANGED, - DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, userHandle); + DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, userId); } - removeCaApprovalsIfNeeded(userHandle); + removeCaApprovalsIfNeeded(userId); } finally { mInjector.binderRestoreCallingIdentity(ident); } @@ -6421,6 +6438,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { "User must be running and unlocked"); } + private void enforceUserUnlocked(int userId, boolean parent) { + if (parent) { + enforceUserUnlocked(getProfileParentId(userId)); + } else { + enforceUserUnlocked(userId); + } + } + private void enforceManageUsers() { final int callingUid = mInjector.binderGetCallingUid(); if (!(isCallerWithSystemUid() || callingUid == Process.ROOT_UID)) { |