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

Commit 6ba10db1 authored by Eran Messeri's avatar Eran Messeri
Browse files

getWifiMacAddress: Enable for profile owner on org-owned device

Allow the profile owner on an organization-owned device to call
getWifiMacAddress.

Part of this change is introducing a new DeviceAdminInfo policy,
USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER, which can be used
to find out if the admin is either device owner or profile owner
on organization-owned device.

Bug: 138709470
Bug: 145308393
Bug: 145336515
Test: atest CtsDevicePolicyManagerTestCases:com.android.cts.devicepolicy.MixedDeviceOwnerTest#testWifi
Test: atest CtsDevicePolicyManagerTestCases:com.android.cts.devicepolicy.MixedManagedProfileOwnerTest#testWifiMacAddress
Test: atest CtsDevicePolicyManagerTestCases:com.android.cts.devicepolicy.OrgOwnedProfileOwnerTest#testWifi
Change-Id: Id790408a07b9dd19530563bd2aa9216a7333e863
parent fb3fdce2
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -54,6 +54,14 @@ import java.util.HashMap;
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.
+8 −1
Original line number Diff line number Diff line
@@ -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.
+25 −16
Original line number Diff line number Diff line
@@ -2748,6 +2748,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);
@@ -2763,6 +2766,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: "
@@ -2869,12 +2876,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)
@@ -5574,6 +5585,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 "
@@ -8071,21 +8089,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;
        return isProfileOwnerOfOrganizationOwnedDevice(
                admin.info.getComponent(), admin.getUserHandle().getIdentifier());
    }
        if (!canProfileOwnerAccessDeviceIds(adminUserId)) {
            Slog.w(LOG_TAG, String.format("Profile owner of user %d does not own the device.",
                    adminUserId));
            return false;
        }
        return true;
    private boolean isProfileOwnerOfOrganizationOwnedDevice(ComponentName who, int userId) {
        return isProfileOwner(who, userId) && canProfileOwnerAccessDeviceIds(userId);
    }
    @Override
@@ -12377,7 +12386,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 {
+15 −2
Original line number Diff line number Diff line
@@ -138,6 +138,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}.
@@ -2114,12 +2116,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.
@@ -2141,6 +2145,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);