Merge "Restrict setting the profile/device owner with a signature-level permission."

This commit is contained in:
Nicolas Prevot
2015-04-24 15:08:01 +00:00
committed by Android (Google) Code Review
4 changed files with 106 additions and 57 deletions

View File

@@ -2651,14 +2651,12 @@ public class DevicePolicyManager {
/**
* @hide
* Sets the given package as the device owner. The package must already be installed and there
* shouldn't be an existing device owner registered, for this call to succeed. Also, this
* method must be called before the device is provisioned.
* Sets the given package as the device owner.
* Same as {@link #setDeviceOwner(String, String)} but without setting a device owner name.
* @param packageName the package name of the application to be registered as the device owner.
* @return whether the package was successfully registered as the device owner.
* @throws IllegalArgumentException if the package name is null or invalid
* @throws IllegalStateException if a device owner is already registered or the device has
* already been provisioned.
* @throws IllegalStateException If the preconditions mentioned are not met.
*/
public boolean setDeviceOwner(String packageName) throws IllegalArgumentException,
IllegalStateException {
@@ -2667,15 +2665,17 @@ public class DevicePolicyManager {
/**
* @hide
* Sets the given package as the device owner. The package must already be installed and there
* shouldn't be an existing device owner registered, for this call to succeed. Also, this
* method must be called before the device is provisioned.
* Sets the given package as the device owner. The package must already be installed. There
* must not already be a device owner.
* Only apps with the MANAGE_PROFILE_AND_DEVICE_OWNERS permission and the shell uid can call
* this method.
* Calling this after the setup phase of the primary user has completed is allowed only if
* the caller is the shell uid, and there are no additional users and no accounts.
* @param packageName the package name of the application to be registered as the device owner.
* @param ownerName the human readable name of the institution that owns this device.
* @return whether the package was successfully registered as the device owner.
* @throws IllegalArgumentException if the package name is null or invalid
* @throws IllegalStateException if a device owner is already registered or the device has
* already been provisioned.
* @throws IllegalStateException If the preconditions mentioned are not met.
*/
public boolean setDeviceOwner(String packageName, String ownerName)
throws IllegalArgumentException, IllegalStateException {
@@ -2961,14 +2961,18 @@ public class DevicePolicyManager {
/**
* @hide
* Sets the given component as the profile owner of the given user profile. The package must
* already be installed and there shouldn't be an existing profile owner registered for this
* user. Only the system can call this API if the user has already completed setup.
* already be installed. There must not already be a profile owner for this user.
* Only apps with the MANAGE_PROFILE_AND_DEVICE_OWNERS permission and the shell uid can call
* this method.
* Calling this after the setup phase of the specified user has completed is allowed only if:
* - the caller is SYSTEM_UID.
* - or the caller is the shell uid, and there are no accounts on the specified user.
* @param admin the component name to be registered as profile owner.
* @param ownerName the human readable name of the organisation associated with this DPM.
* @param userHandle the userId to set the profile owner for.
* @return whether the component was successfully registered as the profile owner.
* @throws IllegalArgumentException if admin is null, the package isn't installed, or
* the user has already been set up.
* @throws IllegalArgumentException if admin is null, the package isn't installed, or the
* preconditions mentioned are not met.
*/
public boolean setProfileOwner(ComponentName admin, String ownerName, int userHandle)
throws IllegalArgumentException {

View File

@@ -1309,6 +1309,14 @@
<permission android:name="android.permission.MANAGE_USERS"
android:protectionLevel="signature|system" />
<!-- @hide Allows an application to set the profile owners and the device owner.
This permission is not available to third party applications.-->
<permission android:name="android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS"
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
android:protectionLevel="signature"
android:label="@string/permlab_manageProfileAndDeviceOwners"
android:description="@string/permdesc_manageProfileAndDeviceOwners" />
<!-- Allows an application to get full detailed information about
recently running tasks, with full fidelity to the real state.
@hide -->

View File

@@ -698,6 +698,12 @@
about currently and recently running tasks. This may allow the app to
discover information about which applications are used on the device.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_manageProfileAndDeviceOwners">Manage profile and device owners</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to set the profile/device owners.
[CHAR LIMIT=NONE] -->
<string name="permdesc_manageProfileAndDeviceOwners">Allows apps to set the profile owners and the device owner.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_reorderTasks">reorder running apps</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->

View File

@@ -3983,15 +3983,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
+ " for device owner");
}
synchronized (this) {
if (!allowedToSetDeviceOwnerOnDevice()) {
throw new IllegalStateException(
"Trying to set device owner but device is already provisioned.");
}
if (mDeviceOwner != null && mDeviceOwner.hasDeviceOwner()) {
throw new IllegalStateException(
"Trying to set device owner but device owner is already set.");
}
enforceCanSetDeviceOwner();
// Shutting down backup manager service permanently.
long ident = Binder.clearCallingIdentity();
@@ -4009,7 +4001,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
// Device owner is not set and does not exist, set it.
mDeviceOwner = DeviceOwner.createWithDeviceOwner(packageName, ownerName);
} else {
// Device owner is not set but a profile owner exists, update Device owner state.
// Device owner state already exists, update it.
mDeviceOwner.setDeviceOwner(packageName, ownerName);
}
mDeviceOwner.writeOwnerFile();
@@ -4225,43 +4217,23 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
if (!mHasFeature) {
return false;
}
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
UserInfo info = mUserManager.getUserInfo(userHandle);
if (info == null) {
// User doesn't exist.
throw new IllegalArgumentException(
"Attempted to set profile owner for invalid userId: " + userHandle);
}
if (info.isGuest()) {
throw new IllegalStateException("Cannot set a profile owner on a guest");
}
if (who == null
|| !DeviceOwner.isInstalledForUser(who.getPackageName(), userHandle)) {
throw new IllegalArgumentException("Component " + who
+ " not installed for userId:" + userHandle);
}
synchronized (this) {
// Only SYSTEM_UID can override the userSetupComplete
if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID
&& hasUserSetupCompleted(userHandle)) {
throw new IllegalStateException(
"Trying to set profile owner but user is already set-up.");
}
enforceCanSetProfileOwner(userHandle);
if (mDeviceOwner == null) {
// Device owner state does not exist, create it.
mDeviceOwner = DeviceOwner.createWithProfileOwner(who, ownerName,
userHandle);
mDeviceOwner.writeOwnerFile();
return true;
} else {
// Device owner already exists, update it.
// Device owner state already exists, update it.
mDeviceOwner.setProfileOwner(who, ownerName, userHandle);
mDeviceOwner.writeOwnerFile();
return true;
}
mDeviceOwner.writeOwnerFile();
return true;
}
}
@@ -4451,18 +4423,77 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
/**
* Device owner can only be set on an unprovisioned device. However, if initiated via "adb",
* we also allow it if no accounts or additional users are present on the device.
* The profile owner can only be set by adb or an app with the MANAGE_PROFILE_AND_DEVICE_OWNERS
* permission.
* The profile owner can only be set before the user setup phase has completed,
* except for:
* - SYSTEM_UID
* - adb if there are not accounts.
*/
private boolean allowedToSetDeviceOwnerOnDevice() {
if (!hasUserSetupCompleted(UserHandle.USER_OWNER)) {
return true;
private void enforceCanSetProfileOwner(int userHandle) {
UserInfo info = mUserManager.getUserInfo(userHandle);
if (info == null) {
// User doesn't exist.
throw new IllegalArgumentException(
"Attempted to set profile owner for invalid userId: " + userHandle);
}
if (info.isGuest()) {
throw new IllegalStateException("Cannot set a profile owner on a guest");
}
if (getProfileOwner(userHandle) != null) {
throw new IllegalStateException("Trying to set the profile owner, but profile owner "
+ "is already set.");
}
int callingUid = Binder.getCallingUid();
if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) {
if (hasUserSetupCompleted(userHandle) &&
AccountManager.get(mContext).getAccountsAsUser(userHandle).length > 0) {
throw new IllegalStateException("Not allowed to set the profile owner because "
+ "there are already some accounts on the profile");
}
return;
}
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS, null);
if (hasUserSetupCompleted(userHandle)
&& UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) {
throw new IllegalStateException("Cannot set the profile owner on a user which is "
+ "already set-up");
}
}
int callingId = Binder.getCallingUid();
return (callingId == Process.SHELL_UID || callingId == Process.ROOT_UID)
&& mUserManager.getUserCount() == 1
&& AccountManager.get(mContext).getAccounts().length == 0;
/**
* The Device owner can only be set by adb or an app with the MANAGE_PROFILE_AND_DEVICE_OWNERS
* permission.
* The device owner can only be set before the setup phase of the primary user has completed,
* except for adb if no accounts or additional users are present on the device.
*/
private void enforceCanSetDeviceOwner() {
if (mDeviceOwner != null && mDeviceOwner.hasDeviceOwner()) {
throw new IllegalStateException("Trying to set the device owner, but device owner "
+ "is already set.");
}
int callingUid = Binder.getCallingUid();
if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) {
if (!hasUserSetupCompleted(UserHandle.USER_OWNER)) {
return;
}
if (mUserManager.getUserCount() > 1) {
throw new IllegalStateException("Not allowed to set the device owner because there "
+ "are already several users on the device");
}
if (AccountManager.get(mContext).getAccounts().length > 0) {
throw new IllegalStateException("Not allowed to set the device owner because there "
+ "are already some accounts on the device");
}
return;
}
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS, null);
if (hasUserSetupCompleted(UserHandle.USER_OWNER)) {
throw new IllegalStateException("Cannot set the device owner if the device is "
+ "already set-up");
}
}
private void enforceCrossUserPermission(int userHandle) {