diff options
-rw-r--r-- | api/current.txt | 2 | ||||
-rw-r--r-- | api/system-current.txt | 2 | ||||
-rw-r--r-- | core/java/android/app/admin/DevicePolicyManager.java | 59 | ||||
-rw-r--r-- | core/java/android/app/admin/IDevicePolicyManager.aidl | 3 | ||||
-rw-r--r-- | services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java | 71 |
5 files changed, 131 insertions, 6 deletions
diff --git a/api/current.txt b/api/current.txt index 29f0a29..f7b668a 100644 --- a/api/current.txt +++ b/api/current.txt @@ -5564,6 +5564,7 @@ package android.app.admin { method public android.os.Bundle getApplicationRestrictions(android.content.ComponentName, java.lang.String); method public boolean getAutoTimeRequired(); method public boolean getCameraDisabled(android.content.ComponentName); + method public java.lang.String getCertInstallerPackage(android.content.ComponentName) throws java.lang.SecurityException; method public boolean getCrossProfileCallerIdDisabled(android.content.ComponentName); method public java.util.List<java.lang.String> getCrossProfileWidgetProviders(android.content.ComponentName); method public int getCurrentFailedPasswordAttempts(); @@ -5612,6 +5613,7 @@ package android.app.admin { method public void setApplicationRestrictions(android.content.ComponentName, java.lang.String, android.os.Bundle); method public void setAutoTimeRequired(android.content.ComponentName, boolean); method public void setCameraDisabled(android.content.ComponentName, boolean); + method public void setCertInstallerPackage(android.content.ComponentName, java.lang.String) throws java.lang.SecurityException; method public void setCrossProfileCallerIdDisabled(android.content.ComponentName, boolean); method public boolean setDeviceInitializer(android.content.ComponentName, android.content.ComponentName, java.lang.String) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException; method public void setGlobalSetting(android.content.ComponentName, java.lang.String, java.lang.String); diff --git a/api/system-current.txt b/api/system-current.txt index 11efc33..10298e4 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -5659,6 +5659,7 @@ package android.app.admin { method public android.os.Bundle getApplicationRestrictions(android.content.ComponentName, java.lang.String); method public boolean getAutoTimeRequired(); method public boolean getCameraDisabled(android.content.ComponentName); + method public java.lang.String getCertInstallerPackage(android.content.ComponentName) throws java.lang.SecurityException; method public boolean getCrossProfileCallerIdDisabled(android.content.ComponentName); method public java.util.List<java.lang.String> getCrossProfileWidgetProviders(android.content.ComponentName); method public int getCurrentFailedPasswordAttempts(); @@ -5714,6 +5715,7 @@ package android.app.admin { method public void setApplicationRestrictions(android.content.ComponentName, java.lang.String, android.os.Bundle); method public void setAutoTimeRequired(android.content.ComponentName, boolean); method public void setCameraDisabled(android.content.ComponentName, boolean); + method public void setCertInstallerPackage(android.content.ComponentName, java.lang.String) throws java.lang.SecurityException; method public void setCrossProfileCallerIdDisabled(android.content.ComponentName, boolean); method public boolean setDeviceInitializer(android.content.ComponentName, android.content.ComponentName, java.lang.String) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException; method public void setGlobalSetting(android.content.ComponentName, java.lang.String, java.lang.String); diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index a659acb..682a468 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -1941,7 +1941,8 @@ public class DevicePolicyManager { /** * Installs the given certificate as a user CA. * - * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Use + * <code>null</code> if calling from a delegated certificate installer. * @param certBuffer encoded form of the certificate to install. * * @return false if the certBuffer cannot be parsed or installation is @@ -1961,7 +1962,8 @@ public class DevicePolicyManager { /** * Uninstalls the given certificate from trusted user CAs, if present. * - * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Use + * <code>null</code> if calling from a delegated certificate installer. * @param certBuffer encoded form of the certificate to remove. */ public void uninstallCaCert(ComponentName admin, byte[] certBuffer) { @@ -1982,7 +1984,8 @@ public class DevicePolicyManager { * If a user has installed any certificates by other means than device policy these will be * included too. * - * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Use + * <code>null</code> if calling from a delegated certificate installer. * @return a List of byte[] arrays, each encoding one user CA certificate. */ public List<byte[]> getInstalledCaCerts(ComponentName admin) { @@ -2009,7 +2012,8 @@ public class DevicePolicyManager { * Uninstalls all custom trusted CA certificates from the profile. Certificates installed by * means other than device policy will also be removed, except for system CA certificates. * - * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Use + * <code>null</code> if calling from a delegated certificate installer. */ public void uninstallAllUserCaCerts(ComponentName admin) { if (mService != null) { @@ -2026,7 +2030,8 @@ public class DevicePolicyManager { /** * Returns whether this certificate is installed as a trusted CA. * - * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Use + * <code>null</code> if calling from a delegated certificate installer. * @param certBuffer encoded form of the certificate to look up. */ public boolean hasCaCertInstalled(ComponentName admin, byte[] certBuffer) { @@ -2083,6 +2088,50 @@ public class DevicePolicyManager { } /** + * Called by a profile owner or device owner to grant access to privileged certificate + * manipulation APIs to a third-party CA certificate installer app. Granted APIs include + * {@link #getInstalledCaCerts}, {@link #hasCaCertInstalled}, {@link #installCaCert}, + * {@link #uninstallCaCert} and {@link #uninstallAllUserCaCerts}. + * <p> + * Delegated certificate installer is a per-user state. The delegated access is persistent until + * it is later cleared by calling this method with a null value or uninstallling the certificate + * installer. + * + * @param who Which {@link DeviceAdminReceiver} this request is associated with. + * @param installerPackage The package name of the certificate installer which will be given + * access. If <code>null</code> is given the current package will be cleared. + */ + public void setCertInstallerPackage(ComponentName who, String installerPackage) + throws SecurityException { + if (mService != null) { + try { + mService.setCertInstallerPackage(who, installerPackage); + } catch (RemoteException e) { + Log.w(TAG, "Failed talking with device policy service", e); + } + } + } + + /** + * Called by a profile owner or device owner to retrieve the certificate installer for the + * current user. null if none is set. + * + * @param who Which {@link DeviceAdminReceiver} this request is associated with. + * @return The package name of the current delegated certificate installer. <code>null</code> + * if none is set. + */ + public String getCertInstallerPackage(ComponentName who) throws SecurityException { + if (mService != null) { + try { + return mService.getCertInstallerPackage(who); + } catch (RemoteException e) { + Log.w(TAG, "Failed talking with device policy service", e); + } + } + return null; + } + + /** * Called by an application that is administering the device to disable all cameras * on the device, for this user. After setting this, no applications running as this user * will be able to access any cameras on the device. diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index f69cf36..9ca52e5 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -132,6 +132,9 @@ interface IDevicePolicyManager { boolean installKeyPair(in ComponentName who, in byte[] privKeyBuffer, in byte[] certBuffer, String alias); void choosePrivateKeyAlias(int uid, in String host, int port, in String url, in String alias, IBinder aliasCallback); + void setCertInstallerPackage(in ComponentName who, String installerPackage); + String getCertInstallerPackage(in ComponentName who); + void addPersistentPreferredActivity(in ComponentName admin, in IntentFilter filter, in ComponentName activity); void clearPackagePersistentPreferredActivities(in ComponentName admin, String packageName); diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 663c919..d07cd98 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -166,6 +166,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private static final String ATTR_PERMISSION_PROVIDER = "permission-provider"; private static final String ATTR_SETUP_COMPLETE = "setup-complete"; + private static final String ATTR_DELEGATED_CERT_INSTALLER = "delegated-cert-installer"; + private static final Set<String> DEVICE_OWNER_USER_RESTRICTIONS; static { DEVICE_OWNER_USER_RESTRICTIONS = new HashSet(); @@ -286,6 +288,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { ComponentName mRestrictionsProvider; + String mDelegatedCertInstallerPackage; + public DevicePolicyData(int userHandle) { mUserHandle = userHandle; } @@ -948,6 +952,21 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { syncDeviceCapabilitiesLocked(policy); saveSettingsLocked(policy.mUserHandle); } + + if (policy.mDelegatedCertInstallerPackage != null && + (packageName == null + || packageName.equals(policy.mDelegatedCertInstallerPackage))) { + try { + // Check if delegated cert installer package is removed. + if (pm.getPackageInfo( + policy.mDelegatedCertInstallerPackage, 0, userHandle) == null) { + policy.mDelegatedCertInstallerPackage = null; + saveSettingsLocked(policy.mUserHandle); + } + } catch (RemoteException e) { + // Shouldn't happen + } + } } } @@ -1332,6 +1351,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { out.attribute(null, ATTR_SETUP_COMPLETE, Boolean.toString(true)); } + if (policy.mDelegatedCertInstallerPackage != null) { + out.attribute(null, ATTR_DELEGATED_CERT_INSTALLER, + policy.mDelegatedCertInstallerPackage); + } + final int N = policy.mAdminList.size(); for (int i=0; i<N; i++) { @@ -1439,6 +1463,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (userSetupComplete != null && Boolean.toString(true).equals(userSetupComplete)) { policy.mUserSetupComplete = true; } + policy.mDelegatedCertInstallerPackage = parser.getAttributeValue(null, + ATTR_DELEGATED_CERT_INSTALLER); type = parser.next(); int outerDepth = parser.getDepth(); @@ -2878,7 +2904,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public void enforceCanManageCaCerts(ComponentName who) { if (who == null) { - mContext.enforceCallingOrSelfPermission(MANAGE_CA_CERTIFICATES, null); + if (!isCallerDelegatedCertInstaller()) { + mContext.enforceCallingOrSelfPermission(MANAGE_CA_CERTIFICATES, null); + } } else { synchronized (this) { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); @@ -2886,6 +2914,25 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } + private boolean isCallerDelegatedCertInstaller() { + final int callingUid = Binder.getCallingUid(); + final int userHandle = UserHandle.getUserId(callingUid); + synchronized (this) { + final DevicePolicyData policy = getUserData(userHandle); + if (policy.mDelegatedCertInstallerPackage == null) { + return false; + } + + try { + int uid = mContext.getPackageManager().getPackageUid( + policy.mDelegatedCertInstallerPackage, userHandle); + return uid == callingUid; + } catch (NameNotFoundException e) { + return false; + } + } + } + @Override public boolean installCaCert(ComponentName admin, byte[] certBuffer) throws RemoteException { enforceCanManageCaCerts(admin); @@ -3036,6 +3083,28 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { }.execute(); } + @Override + public void setCertInstallerPackage(ComponentName who, String installerPackage) + throws SecurityException { + int userHandle = UserHandle.getCallingUserId(); + synchronized (this) { + getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); + DevicePolicyData policy = getUserData(userHandle); + policy.mDelegatedCertInstallerPackage = installerPackage; + saveSettingsLocked(userHandle); + } + } + + @Override + public String getCertInstallerPackage(ComponentName who) throws SecurityException { + int userHandle = UserHandle.getCallingUserId(); + synchronized (this) { + getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); + DevicePolicyData policy = getUserData(userHandle); + return policy.mDelegatedCertInstallerPackage; + } + } + private void wipeDataLocked(boolean wipeExtRequested, String reason) { // If the SD card is encrypted and non-removable, we have to force a wipe. boolean forceExtWipe = !Environment.isExternalStorageRemovable() && isExtStorageEncrypted(); |