diff options
4 files changed, 56 insertions, 19 deletions
diff --git a/core/java/android/app/admin/DeviceAdminInfo.java b/core/java/android/app/admin/DeviceAdminInfo.java index 00903c43b291..63bc40b86aa7 100644 --- a/core/java/android/app/admin/DeviceAdminInfo.java +++ b/core/java/android/app/admin/DeviceAdminInfo.java @@ -55,6 +55,14 @@ public final class DeviceAdminInfo implements Parcelable { static final String TAG = "DeviceAdminInfo"; /** + * A type of policy that this device admin can use: profile owner on an organization-owned + * device. + * + * @hide + */ + public static final int USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER = -3; + + /** * A type of policy that this device admin can use: device owner meta-policy * for an admin that is designated as owner of the device. * diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 39dc51e307f1..34ceb08f39bf 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -9135,7 +9135,14 @@ public class DevicePolicyManager { } /** - * Called by device owner to get the MAC address of the Wi-Fi device. + * Called by device owner, or profile owner on organization-owned device, to get the MAC + * address of the Wi-Fi device. + * + * NOTE: The MAC address returned here should only be used for inventory management and is + * not likely to be the MAC address used by the device to connect to Wi-Fi networks: MAC + * addresses used for scanning and connecting to Wi-Fi networks are randomized by default. + * To get the randomized MAC address used, call + * {@link android.net.wifi.WifiConfiguration#getRandomizedMacAddress}. * * @param admin Which device owner this request is associated with. * @return the MAC address of the Wi-Fi device, or null when the information is not available. diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index dc70f4af8463..cb599be82aa6 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -2754,6 +2754,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return null; } + // Code for handling failure from getActiveAdminWithPolicyForUidLocked to find an admin + // that satisfies the required policy. + // Throws a security exception with the right error message. if (who != null) { final int userId = UserHandle.getUserId(callingUid); final DevicePolicyData policy = getUserData(userId); @@ -2769,6 +2772,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { throw new SecurityException("Admin " + admin.info.getComponent() + " does not own the profile"); } + if (reqPolicy == DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER) { + throw new SecurityException("Admin " + admin.info.getComponent() + + " is not the profile owner on organization-owned device"); + } if (DA_DISALLOWED_POLICIES.contains(reqPolicy) && !isDeviceOwner && !isProfileOwner) { throw new SecurityException("Admin " + admin.info.getComponent() + " is not a device owner or profile owner, so may not use policy: " @@ -2875,12 +2882,16 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { ensureLocked(); final boolean ownsDevice = isDeviceOwner(admin.info.getComponent(), userId); final boolean ownsProfile = isProfileOwner(admin.info.getComponent(), userId); + final boolean ownsProfileOnOrganizationOwnedDevice = + isProfileOwnerOfOrganizationOwnedDevice(admin.info.getComponent(), userId); if (reqPolicy == DeviceAdminInfo.USES_POLICY_DEVICE_OWNER) { return ownsDevice; + } else if (reqPolicy == DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER) { + return ownsDevice || ownsProfileOnOrganizationOwnedDevice; } else if (reqPolicy == DeviceAdminInfo.USES_POLICY_PROFILE_OWNER) { // DO always has the PO power. - return ownsDevice || ownsProfile; + return ownsDevice || ownsProfileOnOrganizationOwnedDevice || ownsProfile; } else { boolean allowedToUsePolicy = ownsDevice || ownsProfile || !DA_DISALLOWED_POLICIES.contains(reqPolicy) @@ -5580,6 +5591,13 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } + private void enforceDeviceOwnerOrProfileOwnerOnOrganizationOwnedDevice(ComponentName who) { + synchronized (getLockObject()) { + getActiveAdminForCallerLocked( + who, DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER); + } + } + private void enforceProfileOwnerOfOrganizationOwnedDevice(ActiveAdmin admin) { if (!isProfileOwnerOfOrganizationOwnedDevice(admin)) { throw new SecurityException(String.format("Provided admin %s is either not a profile " @@ -8077,21 +8095,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return false; } - final int adminUserId = admin.getUserHandle().getIdentifier(); - - if (!isProfileOwner(admin.info.getComponent(), adminUserId)) { - Slog.w(LOG_TAG, String.format("%s is not profile owner of user %d", - admin.info.getComponent(), adminUserId)); - return false; - } - - if (!canProfileOwnerAccessDeviceIds(adminUserId)) { - Slog.w(LOG_TAG, String.format("Profile owner of user %d does not own the device.", - adminUserId)); - return false; - } + return isProfileOwnerOfOrganizationOwnedDevice( + admin.info.getComponent(), admin.getUserHandle().getIdentifier()); + } - return true; + private boolean isProfileOwnerOfOrganizationOwnedDevice(ComponentName who, int userId) { + return isProfileOwner(who, userId) && canProfileOwnerAccessDeviceIds(userId); } @Override @@ -12386,7 +12395,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { @Override public String getWifiMacAddress(ComponentName admin) { // Make sure caller has DO. - enforceDeviceOwner(admin); + enforceDeviceOwnerOrProfileOwnerOnOrganizationOwnedDevice(admin); final long ident = mInjector.binderClearCallingIdentity(); try { diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java index 2bfac2c0aa9b..06b8716c0926 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -140,6 +140,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { permission.MANAGE_USERS, permission.INTERACT_ACROSS_USERS_FULL); public static final String NOT_DEVICE_OWNER_MSG = "does not own the device"; public static final String NOT_PROFILE_OWNER_MSG = "does not own the profile"; + public static final String NOT_ORG_OWNED_PROFILE_OWNER_MSG = + "not the profile owner on organization-owned device"; public static final String ONGOING_CALL_MSG = "ongoing call on the device"; // TODO replace all instances of this with explicit {@link #mServiceContext}. @@ -2116,12 +2118,14 @@ public class DevicePolicyManagerTest extends DpmTestBase { assertTrue(dpm.isAdminActive(admin1)); // Test 2. Caller has DA, but not DO. - assertExpectException(SecurityException.class, /* messageRegex= */ NOT_DEVICE_OWNER_MSG, + assertExpectException(SecurityException.class, + /* messageRegex= */ NOT_ORG_OWNED_PROFILE_OWNER_MSG, () -> dpm.getWifiMacAddress(admin1)); // Test 3. Caller has PO, but not DO. assertTrue(dpm.setProfileOwner(admin1, null, UserHandle.USER_SYSTEM)); - assertExpectException(SecurityException.class, /* messageRegex= */ NOT_DEVICE_OWNER_MSG, + assertExpectException(SecurityException.class, + /* messageRegex= */ NOT_ORG_OWNED_PROFILE_OWNER_MSG, () -> dpm.getWifiMacAddress(admin1)); // Remove PO. @@ -2143,6 +2147,15 @@ public class DevicePolicyManagerTest extends DpmTestBase { assertEquals("11:22:33:44:55:66", dpm.getWifiMacAddress(admin1)); } + public void testGetMacAddressByOrgOwnedPO() throws Exception { + setupProfileOwner(); + configureProfileOwnerOfOrgOwnedDevice(admin1, DpmMockContext.CALLER_USER_HANDLE); + + final String[] macAddresses = new String[]{"11:22:33:44:55:66"}; + when(getServices().wifiManager.getFactoryMacAddresses()).thenReturn(macAddresses); + assertEquals("11:22:33:44:55:66", dpm.getWifiMacAddress(admin1)); + } + public void testReboot() throws Exception { mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS); mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); |