1 package com.android.nfc;
2 
3 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
4 
5 import android.annotation.Nullable;
6 import android.app.ActivityManager;
7 import android.app.admin.DevicePolicyManager;
8 import android.content.ComponentName;
9 import android.content.Context;
10 import android.content.pm.PackageManager;
11 import android.os.Binder;
12 import android.os.UserHandle;
13 import android.os.UserManager;
14 import android.util.Log;
15 import android.util.Pair;
16 
17 import java.util.List;
18 
19 public class NfcPermissions {
20 
21     private static final String TAG = "NfcPermissions";
22 
23     /**
24      * NFC ADMIN permission - only for system apps
25      */
26     private static final String ADMIN_PERM = android.Manifest.permission.WRITE_SECURE_SETTINGS;
27     private static final String ADMIN_PERM_ERROR = "WRITE_SECURE_SETTINGS permission required";
28 
29     /**
30      * Regular NFC permission
31      */
32     static final String NFC_PERMISSION = android.Manifest.permission.NFC;
33     private static final String NFC_PERM_ERROR = "NFC permission required";
34 
35     /**
36      * NFC PREFERRED PAYMENT INFO permission
37      */
38     static final String NFC_PREFERRED_PAYMENT_INFO_PERMISSION =
39             android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO;
40     private static final String NFC_PREFERRED_PAYMENT_INFO_PERM_ERROR =
41             "NFC_PREFERRED_PAYMENT_INFO permission required";
42 
43     /**
44      * NFC SET CONTROLLER ALWAYS ON permission
45      */
46     static final String NFC_SET_CONTROLLER_ALWAYS_ON =
47             android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON;
48     private static final String NFC_SET_CONTROLLER_ALWAYS_ON_ERROR =
49             "NFC_SET_CONTROLLER_ALWAYS_ON permission required";
50 
51     private final Context mContext;
52 
NfcPermissions(Context context)53     public NfcPermissions(Context context) {
54         mContext = context;
55     }
56 
57 
validateUserId(int userId)58     public static void validateUserId(int userId) {
59         if (userId != UserHandle.getUserHandleForUid(Binder.getCallingUid()).getIdentifier()) {
60             throw new SecurityException("userId passed in is not the calling user.");
61         }
62     }
63 
64     /**
65      * Validate whether the profileId belongs to current user
66      */
validateProfileId(Context context, int profileId)67     public static void validateProfileId(Context context, int profileId) {
68         // Propagate the state change to all user profiles
69         UserManager um = context.createContextAsUser(
70                 UserHandle.of(ActivityManager.getCurrentUser()), /*flags=*/0)
71                 .getSystemService(UserManager.class);
72         List<UserHandle> luh = um.getEnabledProfiles();
73 
74         for (UserHandle uh : luh) {
75             if (profileId == uh.getIdentifier()) {
76                 return;
77             }
78         }
79 
80         throw new SecurityException("profileId passed in does not belong to the calling user.");
81     }
82 
enforceAdminPermissions(Context context)83     public static void enforceAdminPermissions(Context context) {
84         context.enforceCallingOrSelfPermission(ADMIN_PERM, ADMIN_PERM_ERROR);
85     }
86 
checkAdminPermissions(Context context)87     public static boolean checkAdminPermissions(Context context) {
88         return context.checkCallingOrSelfPermission(ADMIN_PERM) == PERMISSION_GRANTED;
89     }
90 
enforceUserPermissions(Context context)91     public static void enforceUserPermissions(Context context) {
92         context.enforceCallingOrSelfPermission(NFC_PERMISSION, NFC_PERM_ERROR);
93     }
94 
enforcePreferredPaymentInfoPermissions(Context context)95     public static void enforcePreferredPaymentInfoPermissions(Context context) {
96         context.enforceCallingOrSelfPermission(NFC_PREFERRED_PAYMENT_INFO_PERMISSION,
97                 NFC_PREFERRED_PAYMENT_INFO_PERM_ERROR);
98     }
99 
100     /**
101      * Permission check for android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON
102      */
enforceSetControllerAlwaysOnPermissions(Context context)103     public static void enforceSetControllerAlwaysOnPermissions(Context context) {
104         context.enforceCallingOrSelfPermission(NFC_SET_CONTROLLER_ALWAYS_ON,
105                 NFC_SET_CONTROLLER_ALWAYS_ON_ERROR);
106     }
107 
108     /**
109      * Returns the DevicePolicyManager from context
110      */
retrieveDevicePolicyManagerFromContext(Context context)111     public static DevicePolicyManager retrieveDevicePolicyManagerFromContext(Context context) {
112         DevicePolicyManager devicePolicyManager =
113                 context.getSystemService(DevicePolicyManager.class);
114         if (devicePolicyManager == null
115                 && context.getPackageManager().hasSystemFeature(
116                 PackageManager.FEATURE_DEVICE_ADMIN)) {
117             Log.w(TAG, "Error retrieving DPM service");
118         }
119         return devicePolicyManager;
120     }
121 
122     @Nullable
getDeviceOwner()123     private Pair<UserHandle, ComponentName> getDeviceOwner() {
124         DevicePolicyManager devicePolicyManager =
125                 retrieveDevicePolicyManagerFromContext(mContext);
126         if (devicePolicyManager == null) return null;
127         long ident = Binder.clearCallingIdentity();
128         UserHandle deviceOwnerUser = null;
129         ComponentName deviceOwnerComponent = null;
130         try {
131             deviceOwnerUser = devicePolicyManager.getDeviceOwnerUser();
132             deviceOwnerComponent = devicePolicyManager.getDeviceOwnerComponentOnAnyUser();
133         } finally {
134             Binder.restoreCallingIdentity(ident);
135         }
136         if (deviceOwnerUser == null || deviceOwnerComponent == null) return null;
137 
138         if (deviceOwnerComponent.getPackageName() == null) {
139             // shouldn't happen
140             Log.wtf(TAG, "no package name on device owner component: " + deviceOwnerComponent);
141             return null;
142         }
143         return new Pair<>(deviceOwnerUser, deviceOwnerComponent);
144     }
145 
146     /**
147      * Returns {@code true} if the calling {@code uid} and {@code packageName} is the device owner.
148      */
isDeviceOwner(int uid, @Nullable String packageName)149     public boolean isDeviceOwner(int uid, @Nullable String packageName) {
150         // Cannot determine if the app is DO/PO if packageName is null. So, will return false to be
151         // safe.
152         if (packageName == null) {
153             Log.e(TAG, "isDeviceOwner: packageName is null, returning false");
154             return false;
155         }
156         Pair<UserHandle, ComponentName> deviceOwner = getDeviceOwner();
157         Log.v(TAG, "deviceOwner:" + deviceOwner);
158 
159         // no device owner
160         if (deviceOwner == null) return false;
161 
162         return deviceOwner.first.equals(UserHandle.getUserHandleForUid(uid))
163                 && deviceOwner.second.getPackageName().equals(packageName);
164     }
165 
166     @Nullable
createPackageContextAsUser(int uid)167     private Context createPackageContextAsUser(int uid) {
168         Context userContext = null;
169         try {
170             userContext = mContext.createPackageContextAsUser(mContext.getPackageName(), 0,
171                     UserHandle.getUserHandleForUid(uid));
172         } catch (PackageManager.NameNotFoundException e) {
173             Log.e(TAG, "Unknown package name");
174             return null;
175         }
176         if (userContext == null) {
177             Log.e(TAG, "Unable to retrieve user context for " + uid);
178             return null;
179         }
180         return userContext;
181     }
182 
retrieveDevicePolicyManagerFromUserContext(int uid)183     private DevicePolicyManager retrieveDevicePolicyManagerFromUserContext(int uid) {
184         long ident = Binder.clearCallingIdentity();
185         try {
186             Context userContext = createPackageContextAsUser(uid);
187             if (userContext == null) return null;
188             return retrieveDevicePolicyManagerFromContext(userContext);
189         } finally {
190             Binder.restoreCallingIdentity(ident);
191         }
192     }
193 
194     /**
195      * Returns true if the |callingUid|/|callingPackage| is the profile owner.
196      */
isProfileOwner(int uid, @Nullable String packageName)197     public boolean isProfileOwner(int uid, @Nullable String packageName) {
198         // Cannot determine if the app is DO/PO if packageName is null. So, will return false to be
199         // safe.
200         if (packageName == null) {
201             Log.e(TAG, "isProfileOwner: packageName is null, returning false");
202             return false;
203         }
204         DevicePolicyManager devicePolicyManager =
205                 retrieveDevicePolicyManagerFromUserContext(uid);
206         if (devicePolicyManager == null) return false;
207         return devicePolicyManager.isProfileOwnerApp(packageName);
208     }
209 }
210