Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit be46532c authored by Amith Yamasani's avatar Amith Yamasani
Browse files

Allow profile owners to set user restrictions

Pass the setting along to UserManager.

Fixes a security exception when fetching the profile's enabled state.

Change-Id: If71698cf32c52cce1158cf2027443a339bc58488
parent d80cb24a
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -4947,7 +4947,9 @@ package android.app.admin {
  public class DevicePolicyManager {
    method public void addPersistentPreferredActivity(android.content.ComponentName, android.content.IntentFilter, android.content.ComponentName);
    method public void addUserRestriction(android.content.ComponentName, java.lang.String);
    method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String);
    method public void clearUserRestriction(android.content.ComponentName, java.lang.String);
    method public java.util.List<android.content.ComponentName> getActiveAdmins();
    method public android.os.Bundle getApplicationRestrictions(android.content.ComponentName, java.lang.String);
    method public boolean getCameraDisabled(android.content.ComponentName);
+44 −0
Original line number Diff line number Diff line
@@ -1957,4 +1957,48 @@ public class DevicePolicyManager {
        }
        return null;
    }

    /**
     * Called by a profile or device owner to set a user restriction specified
     * by the key.
     * <p>
     * The calling device admin must be a profile or device owner; if it is not,
     * a security exception will be thrown.
     * 
     * @param admin Which {@link DeviceAdminReceiver} this request is associated
     *            with.
     * @param key The key of the restriction. See the constants in
     *            {@link android.os.UserManager} for the list of keys.
     */
    public void addUserRestriction(ComponentName admin, String key) {
        if (mService != null) {
            try {
                mService.setUserRestriction(admin, key, true);
            } catch (RemoteException e) {
                Log.w(TAG, "Failed talking with device policy service", e);
            }
        }
    }

    /**
     * Called by a profile or device owner to clear a user restriction specified
     * by the key.
     * <p>
     * The calling device admin must be a profile or device owner; if it is not,
     * a security exception will be thrown.
     * 
     * @param admin Which {@link DeviceAdminReceiver} this request is associated
     *            with.
     * @param key The key of the restriction. See the constants in
     *            {@link android.os.UserManager} for the list of keys.
     */
    public void clearUserRestriction(ComponentName admin, String key) {
        if (mService != null) {
            try {
                mService.setUserRestriction(admin, key, false);
            } catch (RemoteException e) {
                Log.w(TAG, "Failed talking with device policy service", e);
            }
        }
    }
}
+2 −0
Original line number Diff line number Diff line
@@ -119,4 +119,6 @@ interface IDevicePolicyManager {

    void setApplicationRestrictions(in ComponentName who, in String packageName, in Bundle settings);
    Bundle getApplicationRestrictions(in ComponentName who, in String packageName);

    void setUserRestriction(in ComponentName who, in String key, boolean enable);
}
+5 −9
Original line number Diff line number Diff line
@@ -300,8 +300,7 @@ public class UserManager {

    /**
     * Sets all the user-wide restrictions for this user.
     * Requires the MANAGE_USERS permission or profile/device owner
     * privileges.
     * Requires the MANAGE_USERS permission.
     * @param restrictions the Bundle containing all the restrictions.
     */
    public void setUserRestrictions(Bundle restrictions) {
@@ -310,8 +309,7 @@ public class UserManager {

    /**
     * Sets all the user-wide restrictions for the specified user.
     * Requires the MANAGE_USERS permission or profile/device owner
     * privileges.
     * Requires the MANAGE_USERS permission.
     * @param restrictions the Bundle containing all the restrictions.
     * @param userHandle the UserHandle of the user for whom to set the restrictions.
     */
@@ -325,8 +323,7 @@ public class UserManager {

    /**
     * Sets the value of a specific restriction.
     * Requires the MANAGE_USERS permission or profile/device owner
     * privileges.
     * Requires the MANAGE_USERS permission.
     * @param key the key of the restriction
     * @param value the value for the restriction
     */
@@ -339,8 +336,7 @@ public class UserManager {
    /**
     * @hide
     * Sets the value of a specific restriction on a specific user.
     * Requires the {@link android.Manifest.permission#MANAGE_USERS} permission or profile/device owner
     * privileges.
     * Requires the MANAGE_USERS permission.
     * @param key the key of the restriction
     * @param value the value for the restriction
     * @param userHandle the user whose restriction is to be changed.
+53 −82
Original line number Diff line number Diff line
@@ -22,7 +22,6 @@ import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.ActivityThread;
import android.app.admin.DevicePolicyManager;
import android.app.IStopUserCallback;
import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
@@ -263,9 +262,21 @@ public class UserManagerService extends IUserManager.Stub {
        if (userId != UserHandle.getCallingUserId()) {
            checkManageUsersPermission("getting profiles related to user " + userId);
        }
        final long ident = Binder.clearCallingIdentity();
        try {
            synchronized (mPackagesLock) {
            // Getting the service here is not good for testing purposes. However, this service
            // is not available when UserManagerService starts up so we need a lazy load.
                return getProfilesLocked(userId, enabledOnly);
            }
        } finally {
            Binder.restoreCallingIdentity(ident);
        }
    }

    /** Assume permissions already checked and caller's identity cleared */
    private List<UserInfo> getProfilesLocked(int userId, boolean enabledOnly) {
        // Getting the service here is not good for testing purposes.
        // However, this service is not available when UserManagerService starts
        // up so we need a lazy load.

        DevicePolicyManager dpm = null;
        if (enabledOnly) {
@@ -288,20 +299,20 @@ public class UserManagerService extends IUserManager.Stub {
                    }
                } else {
                    Log.w(LOG_TAG,
                                "Attempting to reach DevicePolicyManager before it was started");
                        // TODO: There might be system apps that need to call this. Make sure that
                        // DevicePolicyManagerService is ready at that time (otherwise, any default
                        // value is a bad one).
                            "Attempting to reach DevicePolicyManager before it is started");
                    // TODO: There might be system apps that need to call this.
                    // Make sure that DevicePolicyManagerService is ready at that
                    // time (otherwise, any default value is a bad one).
                    throw new IllegalArgumentException(String.format(
                            "Attempting to get enabled profiles for %d before "
                                + "DevicePolicyManagerService has been started.", userId));
                                    + "DevicePolicyManagerService has been started.",
                            userId));
                }
            }
            users.add(profile);
        }
        return users;
    }
    }

    private boolean isProfileOf(UserInfo user, UserInfo profile) {
        return user.id == profile.id ||
@@ -459,13 +470,13 @@ public class UserManagerService extends IUserManager.Stub {

        synchronized (mPackagesLock) {
            Bundle restrictions = mUserRestrictions.get(userId);
            return restrictions != null ? restrictions : Bundle.EMPTY;
            return restrictions != null ? new Bundle(restrictions) : new Bundle();
        }
    }

    @Override
    public void setUserRestrictions(Bundle restrictions, int userId) {
        checkProfileOwnerOrManageUsersPermission("setUserRestrictions");
        checkManageUsersPermission("setUserRestrictions");
        if (restrictions == null) return;

        synchronized (mPackagesLock) {
@@ -491,51 +502,14 @@ public class UserManagerService extends IUserManager.Stub {
     * @param message used as message if SecurityException is thrown
     * @throws SecurityException if the caller is not system or root
     */
    private final void checkManageUsersPermission(String message) {
        final int uid = Binder.getCallingUid();

        if (missingManageUsersPermission(uid)) {
            throw new SecurityException("You need MANAGE_USERS permission to: " + message);
        }
    }

    /**
     * Enforces that only the system UID, root's UID, apps that have the
     * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS}
     * permission, the profile owner, or the device owner can make certain calls to the
     * UserManager.
     *
     * @param message used as message if SecurityException is thrown
     * @throws SecurityException if the caller is not system, root, or device
     * owner
     */
    private final void checkProfileOwnerOrManageUsersPermission(String message) {
    private static final void checkManageUsersPermission(String message) {
        final int uid = Binder.getCallingUid();
        boolean isProfileOwner = false;
        if (mContext != null && mContext.getPackageManager() != null) {
            String[] pkgs = mContext.getPackageManager().getPackagesForUid(uid);
            DevicePolicyManager dpm =
                    (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
            if (dpm != null) {
                for (String pkg : pkgs) {
                    if (dpm.isDeviceOwnerApp(pkg) || dpm.isProfileOwnerApp(pkg)) {
                        isProfileOwner = true;
                    }
                }
            }
        }

        if (missingManageUsersPermission(uid) && !isProfileOwner) {
            throw new SecurityException(
                    "You need MANAGE_USERS permission or device owner privileges to: " + message);
        }
    }

    private boolean missingManageUsersPermission(int uid) {
        return uid != Process.SYSTEM_UID && uid != 0
        if (uid != Process.SYSTEM_UID && uid != 0
                && ActivityManager.checkComponentPermission(
                        android.Manifest.permission.MANAGE_USERS,
                        uid, -1, true) != PackageManager.PERMISSION_GRANTED;
                        uid, -1, true) != PackageManager.PERMISSION_GRANTED) {
            throw new SecurityException("You need MANAGE_USERS permission to: " + message);
        }
    }

    private void writeBitmapLocked(UserInfo info, Bitmap bitmap) {
@@ -1240,8 +1214,7 @@ public class UserManagerService extends IUserManager.Stub {
    public Bundle getApplicationRestrictionsForUser(String packageName, int userId) {
        if (UserHandle.getCallingUserId() != userId
                || !UserHandle.isSameApp(Binder.getCallingUid(), getUidForPackage(packageName))) {
            checkProfileOwnerOrManageUsersPermission(
                    "Only system or device owner can get restrictions for other users/apps");
            checkManageUsersPermission("Only system can get restrictions for other users/apps");
        }
        synchronized (mPackagesLock) {
            // Read the restrictions from XML
@@ -1254,8 +1227,7 @@ public class UserManagerService extends IUserManager.Stub {
            int userId) {
        if (UserHandle.getCallingUserId() != userId
                || !UserHandle.isSameApp(Binder.getCallingUid(), getUidForPackage(packageName))) {
            checkProfileOwnerOrManageUsersPermission(
                    "Only system or device owner can set restrictions for other users/apps");
            checkManageUsersPermission("Only system can set restrictions for other users/apps");
        }
        synchronized (mPackagesLock) {
            // Write the restrictions to XML
@@ -1357,8 +1329,7 @@ public class UserManagerService extends IUserManager.Stub {

    @Override
    public void removeRestrictions() {
        checkProfileOwnerOrManageUsersPermission(
                "Only system or device owner can remove restrictions");
        checkManageUsersPermission("Only system can remove restrictions");
        final int userHandle = UserHandle.getCallingUserId();
        removeRestrictionsForUser(userHandle, true);
    }
Loading