summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/current.txt2
-rw-r--r--api/system-current.txt2
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java59
-rw-r--r--core/java/android/app/admin/IDevicePolicyManager.aidl3
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java71
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();