• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.wifi.util;
18 
19 import static android.Manifest.permission.ACCESS_FINE_LOCATION;
20 import static android.Manifest.permission.ENTER_CAR_MODE_PRIORITIZED;
21 import static android.Manifest.permission.NEARBY_WIFI_DEVICES;
22 import static android.Manifest.permission.RENOUNCE_PERMISSIONS;
23 import static android.Manifest.permission.REQUEST_COMPANION_PROFILE_AUTOMOTIVE_PROJECTION;
24 import static android.content.pm.PackageManager.GET_PERMISSIONS;
25 import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
26 
27 import android.Manifest;
28 import android.annotation.NonNull;
29 import android.annotation.Nullable;
30 import android.app.AppOpsManager;
31 import android.app.admin.DevicePolicyManager;
32 import android.app.admin.WifiSsidPolicy;
33 import android.content.AttributionSource;
34 import android.content.ComponentName;
35 import android.content.Context;
36 import android.content.pm.ApplicationInfo;
37 import android.content.pm.PackageInfo;
38 import android.content.pm.PackageManager;
39 import android.location.LocationManager;
40 import android.net.NetworkStack;
41 import android.net.wifi.SecurityParams;
42 import android.net.wifi.WifiConfiguration;
43 import android.net.wifi.WifiInfo;
44 import android.net.wifi.WifiSsid;
45 import android.os.Binder;
46 import android.os.Build;
47 import android.os.Process;
48 import android.os.UserHandle;
49 import android.os.UserManager;
50 import android.permission.PermissionManager;
51 import android.provider.Settings;
52 import android.util.ArraySet;
53 import android.util.EventLog;
54 import android.util.Log;
55 import android.util.Pair;
56 import android.util.SparseBooleanArray;
57 
58 import androidx.annotation.RequiresApi;
59 
60 import com.android.internal.annotations.GuardedBy;
61 import com.android.modules.utils.build.SdkLevel;
62 import com.android.server.wifi.FrameworkFacade;
63 import com.android.server.wifi.WifiInjector;
64 import com.android.server.wifi.WifiLog;
65 import com.android.wifi.resources.R;
66 
67 import java.util.Arrays;
68 import java.util.Set;
69 
70 /**
71  * A wifi permissions utility assessing permissions
72  * for getting scan results by a package.
73  */
74 public class WifiPermissionsUtil {
75     private static final String TAG = "WifiPermissionsUtil";
76 
77     private static final int APP_INFO_FLAGS_SYSTEM_APP =
78             ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
79     private final WifiPermissionsWrapper mWifiPermissionsWrapper;
80     private final Context mContext;
81     private final FrameworkFacade mFrameworkFacade;
82     private final AppOpsManager mAppOps;
83     private final UserManager mUserManager;
84     private final PermissionManager mPermissionManager;
85     private final Object mLock = new Object();
86     @GuardedBy("mLock")
87     private LocationManager mLocationManager;
88     private WifiLog mLog;
89     private boolean mVerboseLoggingEnabled;
90     private final SparseBooleanArray mOemPrivilegedAdminUidCache = new SparseBooleanArray();
91 
WifiPermissionsUtil(WifiPermissionsWrapper wifiPermissionsWrapper, Context context, UserManager userManager, WifiInjector wifiInjector)92     public WifiPermissionsUtil(WifiPermissionsWrapper wifiPermissionsWrapper,
93             Context context, UserManager userManager, WifiInjector wifiInjector) {
94         mWifiPermissionsWrapper = wifiPermissionsWrapper;
95         mContext = context;
96         mFrameworkFacade = wifiInjector.getFrameworkFacade();
97         mUserManager = userManager;
98         mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
99         mPermissionManager = mContext.getSystemService(PermissionManager.class);
100         mLog = wifiInjector.makeLog(TAG);
101     }
102 
103 
104     /**
105      * A class to store binder caller information.
106      */
107     public static final class CallerIdentity {
108         int mUid;
109         int mPid;
110         String mPackageName;
111         String mFeatureId;
112 
CallerIdentity(int uid, int pid, String packageName, String featureId)113         public CallerIdentity(int uid, int pid, String packageName, String featureId) {
114             mUid = uid;
115             mPid = pid;
116             mPackageName = packageName;
117             mFeatureId = featureId;
118         }
119 
getUid()120         public int getUid() {
121             return mUid;
122         }
123 
getPid()124         public int getPid() {
125             return mPid;
126         }
127 
getPackageName()128         public String getPackageName() {
129             return mPackageName;
130         }
131 
getFeatureId()132         public String getFeatureId() {
133             return mFeatureId;
134         }
135 
136         @NonNull
137         @Override
toString()138         public String toString() {
139             return "CallerIdentity{"
140                     + "Uid= " + mUid
141                     + ", Pid= " + mPid
142                     + ", PackageName= " + mPackageName
143                     + ", FeatureId= " + mFeatureId
144                     + '}';
145         }
146     }
147 
148     /**
149      * Checks if the app has the permission to override Wi-Fi network configuration or not.
150      *
151      * @param uid uid of the app.
152      * @return true if the app does have the permission, false otherwise.
153      */
checkConfigOverridePermission(int uid)154     public boolean checkConfigOverridePermission(int uid) {
155         return mWifiPermissionsWrapper.getOverrideWifiConfigPermission(uid)
156                 == PackageManager.PERMISSION_GRANTED;
157     }
158 
159     /**
160      * Check and enforce Coarse or Fine Location permission (depending on target SDK).
161      *
162      * @param pkgName PackageName of the application requesting access
163      * @param featureId The feature in the package
164      * @param uid The uid of the package
165      */
enforceLocationPermission(String pkgName, @Nullable String featureId, int uid)166     public void enforceLocationPermission(String pkgName, @Nullable String featureId, int uid) {
167         if (!checkCallersLocationPermission(pkgName, featureId,
168                 uid, /* coarseForTargetSdkLessThanQ */ true, null)) {
169             throw new SecurityException(
170                     "UID " + uid + " does not have Coarse/Fine Location permission");
171         }
172     }
173 
174     /**
175      * Version of enforceNearbyDevicesPermission that do not throw an exception.
176      */
checkNearbyDevicesPermission(AttributionSource attributionSource, boolean checkForLocation, String message)177     public boolean checkNearbyDevicesPermission(AttributionSource attributionSource,
178             boolean checkForLocation, String message) {
179         try {
180             enforceNearbyDevicesPermission(attributionSource, checkForLocation, message);
181         } catch (SecurityException e) {
182             return false;
183         }
184         return true;
185     }
186 
187     /**
188      * Check and enforce NEARBY_WIFI_DEVICES permission and optionally enforce for either location
189      * disavowal or location permission.
190      *
191      * Note, this is only callable on SDK version T and later.
192      *
193      * @param attributionSource AttributionSource of the caller.
194      * @param checkForLocation If true will require the caller to either disavow location
195      *                         or actually have location permission.
196      * @param message String to log as the reason for performing permission checks.
197      */
enforceNearbyDevicesPermission(AttributionSource attributionSource, boolean checkForLocation, String message)198     public void enforceNearbyDevicesPermission(AttributionSource attributionSource,
199             boolean checkForLocation, String message) throws SecurityException {
200         if (!SdkLevel.isAtLeastT()) {
201             Log.wtf(TAG, "enforceNearbyDevicesPermission should never be called on pre-T "
202                     + "devices");
203             throw new SecurityException("enforceNearbyDevicesPermission requires at least "
204                     + "Android T");
205         }
206         if (attributionSource == null) {
207             throw new SecurityException("enforceNearbyDevicesPermission attributionSource is null");
208         }
209         if (mVerboseLoggingEnabled) {
210             Log.v(TAG, "enforceNearbyDevicesPermission(attributionSource="
211                     + attributionSource + ", checkForLocation=" + checkForLocation);
212         }
213         if (!attributionSource.checkCallingUid()) {
214             throw new SecurityException("enforceNearbyDevicesPermission invalid attribution source="
215                     + attributionSource);
216         }
217         String packageName = attributionSource.getPackageName();
218         int uid = attributionSource.getUid();
219         checkPackage(uid, packageName);
220         // Apps with NETWORK_SETTINGS, NETWORK_SETUP_WIZARD, NETWORK_MANAGED_PROVISIONING,
221         // NETWORK_STACK & MAINLINE_NETWORK_STACK, RADIO_SCAN_WITHOUT_LOCATION are granted a bypass.
222         if (checkNetworkSettingsPermission(uid) || checkNetworkSetupWizardPermission(uid)
223                 || checkNetworkManagedProvisioningPermission(uid)
224                 || checkNetworkStackPermission(uid) || checkMainlineNetworkStackPermission(uid)
225                 || checkScanWithoutLocationPermission(uid)) {
226             return;
227         }
228 
229         int permissionCheckResult = mPermissionManager.checkPermissionForDataDelivery(
230                 Manifest.permission.NEARBY_WIFI_DEVICES, attributionSource, message);
231         if (permissionCheckResult != PermissionManager.PERMISSION_GRANTED) {
232             throw new SecurityException("package=" + packageName + " UID=" + uid
233                     + " does not have nearby devices permission.");
234         }
235         if (mVerboseLoggingEnabled) {
236             Log.v(TAG, "pkg=" + packageName + " has NEARBY_WIFI_DEVICES permission.");
237         }
238         if (!checkForLocation) {
239             // No need to check for location permission. All done now and return.
240             return;
241         }
242 
243         // There are 2 ways to disavow location. Skip location permission check if any of the
244         // 2 ways are used to disavow location usage.
245         // First check if the app renounced location.
246         // Check every step along the attribution chain for a renouncement.
247         AttributionSource currentAttrib = attributionSource;
248         while (true) {
249             int curUid = currentAttrib.getUid();
250             String curPackageName = currentAttrib.getPackageName();
251             // If location has been renounced anywhere in the chain we treat it as a disavowal.
252             if (currentAttrib.getRenouncedPermissions().contains(ACCESS_FINE_LOCATION)
253                     && mWifiPermissionsWrapper.getUidPermission(RENOUNCE_PERMISSIONS, curUid)
254                     == PackageManager.PERMISSION_GRANTED) {
255                 if (mVerboseLoggingEnabled) {
256                     Log.v(TAG, "package=" + curPackageName + " UID=" + curUid
257                             + " has renounced location permission - bypassing location check.");
258                 }
259                 return;
260             }
261             AttributionSource nextAttrib = currentAttrib.getNext();
262             if (nextAttrib == null) {
263                 break;
264             }
265             currentAttrib = nextAttrib;
266         }
267         // If the app did not renounce location, check if "neverForLocation" is set.
268         PackageManager pm = mContext.getPackageManager();
269         try {
270             PackageInfo pkgInfo = pm.getPackageInfo(packageName,
271                     GET_PERMISSIONS | MATCH_UNINSTALLED_PACKAGES);
272             int requestedPermissionsLength = pkgInfo.requestedPermissions == null
273                     || pkgInfo.requestedPermissionsFlags == null ? 0
274                     : pkgInfo.requestedPermissions.length;
275             if (requestedPermissionsLength == 0) {
276                 Log.e(TAG, "package=" + packageName + " unexpectedly has null "
277                         + "requestedPermissions or requestPermissionFlags.");
278             }
279             for (int i = 0; i < requestedPermissionsLength; i++) {
280                 if (pkgInfo.requestedPermissions[i].equals(NEARBY_WIFI_DEVICES)
281                         && (pkgInfo.requestedPermissionsFlags[i]
282                         & PackageInfo.REQUESTED_PERMISSION_NEVER_FOR_LOCATION) != 0) {
283                     if (mVerboseLoggingEnabled) {
284                         Log.v(TAG, "package=" + packageName + " UID=" + uid
285                                 + " has declared neverForLocation - bypassing location check.");
286                     }
287                     return;
288                 }
289             }
290         } catch (PackageManager.NameNotFoundException e) {
291             Log.w(TAG, "Could not find package for disavowal check: " + packageName);
292         }
293         // App did not disavow location. Check for location permission and location mode.
294         long ident = Binder.clearCallingIdentity();
295         try {
296             if (!isLocationModeEnabled()) {
297                 if (mVerboseLoggingEnabled) {
298                     Log.v(TAG, "enforceNearbyDevicesPermission(pkg=" + packageName + ", uid=" + uid
299                             + "): "
300                             + "location is disabled");
301                 }
302                 throw new SecurityException("Location mode is disabled for the device");
303             }
304         } finally {
305             Binder.restoreCallingIdentity(ident);
306         }
307         if (mPermissionManager.checkPermissionForDataDelivery(
308                 ACCESS_FINE_LOCATION, attributionSource, message)
309                 == PermissionManager.PERMISSION_GRANTED) {
310             if (mVerboseLoggingEnabled) {
311                 Log.v(TAG, "package=" + packageName + " UID=" + uid + " has location permission.");
312             }
313             return;
314         }
315         throw new SecurityException("package=" + packageName + ", UID=" + uid
316                 + " does not have Fine Location permission");
317     }
318 
319     /**
320      * Checks whether than the target SDK of the package is less than the specified version code.
321      */
isTargetSdkLessThan(String packageName, int versionCode, int callingUid)322     public boolean isTargetSdkLessThan(String packageName, int versionCode, int callingUid) {
323         long ident = Binder.clearCallingIdentity();
324         try {
325             final int targetSdkVersion;
326             if (SdkLevel.isAtLeastS()) {
327                 // >= S, use the lightweight API to just get the target SDK version.
328                 Context userContext = createPackageContextAsUser(callingUid);
329                 if (userContext == null) return false;
330                 targetSdkVersion = userContext.getPackageManager().getTargetSdkVersion(packageName);
331             } else {
332                 // < S, use the heavyweight API to get all package info.
333                 targetSdkVersion = mContext.getPackageManager().getApplicationInfoAsUser(
334                         packageName, 0,
335                         UserHandle.getUserHandleForUid(callingUid)).targetSdkVersion;
336             }
337             return targetSdkVersion < versionCode;
338         } catch (PackageManager.NameNotFoundException e) {
339             // In case of exception, assume unknown app (more strict checking)
340             // Note: This case will never happen since checkPackage is
341             // called to verify validity before checking App's version.
342             return false;
343         } finally {
344             Binder.restoreCallingIdentity(ident);
345         }
346     }
347 
348     /**
349      * Returns the global demo mode of the device. Note that there is a
350      * UserManager.isDeviceInDemoMode(Context) which does the same thing - but is not a
351      * public/system API (whereas the Settings.Global.DEVICE_DEMO_MODE is a System API).
352      */
isDeviceInDemoMode(Context context)353     public boolean isDeviceInDemoMode(Context context) {
354         return Settings.Global.getInt(context.getContentResolver(),
355                 Settings.Global.DEVICE_DEMO_MODE, 0) > 0;
356     }
357 
358     /**
359      * Checks that calling process has android.Manifest.permission.ACCESS_FINE_LOCATION or
360      * android.Manifest.permission.ACCESS_FINE_LOCATION (depending on config/targetSDK leve)
361      * and a corresponding app op is allowed for this package and uid.
362      *
363      * @param pkgName PackageName of the application requesting access
364      * @param featureId The feature in the package
365      * @param uid The uid of the package
366      * @param coarseForTargetSdkLessThanQ If true and the targetSDK < Q then will check for COARSE
367      *                                    else (false or targetSDK >= Q) then will check for FINE
368      * @param message A message describing why the permission was checked. Only needed if this is
369      *                not inside of a two-way binder call from the data receiver
370      */
checkCallersLocationPermission(String pkgName, @Nullable String featureId, int uid, boolean coarseForTargetSdkLessThanQ, @Nullable String message)371     public boolean checkCallersLocationPermission(String pkgName, @Nullable String featureId,
372             int uid, boolean coarseForTargetSdkLessThanQ, @Nullable String message) {
373         boolean isTargetSdkLessThanQ = isTargetSdkLessThan(pkgName, Build.VERSION_CODES.Q, uid);
374 
375         String permissionType = ACCESS_FINE_LOCATION;
376         if (coarseForTargetSdkLessThanQ && isTargetSdkLessThanQ) {
377             // Having FINE permission implies having COARSE permission (but not the reverse)
378             permissionType = Manifest.permission.ACCESS_COARSE_LOCATION;
379         }
380         if (mWifiPermissionsWrapper.getUidPermission(permissionType, uid)
381                 == PackageManager.PERMISSION_DENIED) {
382             if (mVerboseLoggingEnabled) {
383                 Log.v(TAG, "checkCallersLocationPermission(" + pkgName + "): uid " + uid
384                         + " doesn't have permission " + permissionType);
385             }
386             return false;
387         }
388 
389         // Always checking FINE - even if will not enforce. This will record the request for FINE
390         // so that a location request by the app is surfaced to the user.
391         boolean isFineLocationAllowed = noteAppOpAllowed(
392                 AppOpsManager.OPSTR_FINE_LOCATION, pkgName, featureId, uid, message);
393         if (isFineLocationAllowed) {
394             if (mVerboseLoggingEnabled) {
395                 Log.v(TAG, "checkCallersLocationPermission(" + pkgName + "): ok because uid " + uid
396                         + " has app-op " + AppOpsManager.OPSTR_FINE_LOCATION);
397             }
398             return true;
399         }
400         if (coarseForTargetSdkLessThanQ && isTargetSdkLessThanQ) {
401             boolean allowed = noteAppOpAllowed(AppOpsManager.OPSTR_COARSE_LOCATION, pkgName,
402                     featureId, uid, message);
403             if (mVerboseLoggingEnabled) {
404                 Log.v(TAG, "checkCallersLocationPermission(" + pkgName + "): returning " + allowed
405                         + " because uid " + uid + (allowed ? "has" : "doesn't have") + " app-op "
406                         + AppOpsManager.OPSTR_COARSE_LOCATION);
407             }
408             return allowed;
409         }
410         if (mVerboseLoggingEnabled) {
411             Log.v(TAG, "checkCallersLocationPermission(" + pkgName + "): returning false for " + uid
412                     + ": coarseForTargetSdkLessThanQ=" + coarseForTargetSdkLessThanQ
413                     + ", isTargetSdkLessThanQ=" + isTargetSdkLessThanQ);
414 
415         }
416         return false;
417     }
418 
419     /**
420      * Check and enforce Fine Location permission.
421      *
422      * @param pkgName PackageName of the application requesting access
423      * @param featureId The feature in the package
424      * @param uid The uid of the package
425      */
enforceFineLocationPermission(String pkgName, @Nullable String featureId, int uid)426     public void enforceFineLocationPermission(String pkgName, @Nullable String featureId,
427             int uid) {
428         if (!checkCallersFineLocationPermission(pkgName, featureId, uid, false, false)) {
429             throw new SecurityException("UID " + uid + " does not have Fine Location permission");
430         }
431     }
432 
433     /**
434      * Checks that calling process has android.Manifest.permission.ACCESS_FINE_LOCATION
435      * and a corresponding app op is allowed for this package and uid.
436      *
437      * @param pkgName PackageName of the application requesting access
438      * @param featureId The feature in the package
439      * @param uid The uid of the package
440      * @param hideFromAppOps True to invoke {@link AppOpsManager#checkOp(int, int, String)}, false
441      *                       to invoke {@link AppOpsManager#noteOp(String, int, String, String,
442      *                       String)}.
443      * @param ignoreLocationSettings Whether this request can bypass location settings.
444      */
checkCallersFineLocationPermission(String pkgName, @Nullable String featureId, int uid, boolean hideFromAppOps, boolean ignoreLocationSettings)445     private boolean checkCallersFineLocationPermission(String pkgName, @Nullable String featureId,
446             int uid, boolean hideFromAppOps, boolean ignoreLocationSettings) {
447         // Having FINE permission implies having COARSE permission (but not the reverse)
448         if (mWifiPermissionsWrapper.getUidPermission(
449                 ACCESS_FINE_LOCATION, uid)
450                 == PackageManager.PERMISSION_DENIED) {
451             return false;
452         }
453 
454         boolean isAllowed;
455         if (hideFromAppOps) {
456             // Don't note the operation, just check if the app is allowed to perform the operation.
457             isAllowed = checkAppOpAllowed(AppOpsManager.OPSTR_FINE_LOCATION, pkgName, uid);
458         } else {
459             isAllowed = noteAppOpAllowed(AppOpsManager.OPSTR_FINE_LOCATION, pkgName, featureId, uid,
460                     null);
461         }
462         // If the ignoreLocationSettings is true, we always return true. This is for the emergency
463         // location service use case. But still notify the operation manager.
464         return isAllowed || ignoreLocationSettings;
465     }
466 
467     /**
468      * Check and enforce Coarse Location permission.
469      *
470      * @param pkgName PackageName of the application requesting access.
471      * @param featureId The feature in the package.
472      * @param uid The uid of the package.
473      */
enforceCoarseLocationPermission(String pkgName, @Nullable String featureId, int uid)474     public void enforceCoarseLocationPermission(String pkgName, @Nullable String featureId,
475             int uid) {
476         if (!checkCallersCoarseLocationPermission(pkgName, featureId,
477                 uid, null)) {
478             throw new SecurityException(
479                     "UID " + uid + " does not have Coarse Location permission");
480         }
481     }
482 
483     /**
484      * Checks that calling process has android.Manifest.permission.ACCESS_COARSE_LOCATION
485      * and a corresponding app op is allowed for this package and uid.
486      *
487      * @param pkgName PackageName of the application requesting access.
488      * @param featureId The feature in the package.
489      * @param uid The uid of the package.
490      * @param message A message describing why the permission was checked. Only needed if this is
491      *                not inside of a two-way binder call from the data receiver.
492      */
checkCallersCoarseLocationPermission(String pkgName, @Nullable String featureId, int uid, @Nullable String message)493     public boolean checkCallersCoarseLocationPermission(String pkgName, @Nullable String featureId,
494             int uid, @Nullable String message) {
495         if (mWifiPermissionsWrapper.getUidPermission(
496                 Manifest.permission.ACCESS_COARSE_LOCATION, uid)
497                 == PackageManager.PERMISSION_DENIED) {
498             if (mVerboseLoggingEnabled) {
499                 Log.v(TAG, "checkCallersCoarseLocationPermission(" + pkgName + "): uid " + uid
500                         + " doesn't have ACCESS_COARSE_LOCATION permission ");
501             }
502             return false;
503         }
504         boolean allowed = noteAppOpAllowed(AppOpsManager.OPSTR_COARSE_LOCATION, pkgName,
505                     featureId, uid, message);
506         if (mVerboseLoggingEnabled) {
507             Log.v(TAG, "checkCallersCoarseLocationPermission(" + pkgName + "): returning "
508                     + allowed + " because uid " + uid + (allowed ? "has" : "doesn't have")
509                     + " app-op " + AppOpsManager.OPSTR_COARSE_LOCATION);
510         }
511         return allowed;
512     }
513 
514     /**
515      * Checks that calling process has android.Manifest.permission.LOCATION_HARDWARE.
516      *
517      * @param uid The uid of the package
518      */
checkCallersHardwareLocationPermission(int uid)519     public boolean checkCallersHardwareLocationPermission(int uid) {
520         return mWifiPermissionsWrapper.getUidPermission(Manifest.permission.LOCATION_HARDWARE, uid)
521                 == PackageManager.PERMISSION_GRANTED;
522     }
523 
524     /**
525      * API to determine if the caller has permissions to get scan results. Throws SecurityException
526      * if the caller has no permission.
527      * @param pkgName package name of the application requesting access
528      * @param featureId The feature in the package
529      * @param uid The uid of the package
530      * @param message A message describing why the permission was checked. Only needed if this is
531      *                not inside of a two-way binder call from the data receiver
532      */
enforceCanAccessScanResults(String pkgName, @Nullable String featureId, int uid, @Nullable String message)533     public void enforceCanAccessScanResults(String pkgName, @Nullable String featureId, int uid,
534             @Nullable String message)
535             throws SecurityException {
536         checkPackage(uid, pkgName);
537 
538         // Apps with NETWORK_SETTINGS, NETWORK_SETUP_WIZARD, NETWORK_MANAGED_PROVISIONING,
539         // NETWORK_STACK & MAINLINE_NETWORK_STACK, RADIO_SCAN_WITHOUT_LOCATION are granted a bypass.
540         if (checkNetworkSettingsPermission(uid) || checkNetworkSetupWizardPermission(uid)
541                 || checkNetworkManagedProvisioningPermission(uid)
542                 || checkNetworkStackPermission(uid) || checkMainlineNetworkStackPermission(uid)
543                 || checkScanWithoutLocationPermission(uid)) {
544             return;
545         }
546 
547         // Location mode must be enabled
548         if (!isLocationModeEnabled()) {
549             if (mVerboseLoggingEnabled) {
550                 Log.v(TAG, "enforceCanAccessScanResults(pkg=" + pkgName + ", uid=" + uid + "): "
551                         + "location is disabled");
552             }
553             // Location mode is disabled, scan results cannot be returned
554             throw new SecurityException("Location mode is disabled for the device");
555         }
556 
557         // Check if the calling Uid has CAN_READ_PEER_MAC_ADDRESS permission.
558         boolean canCallingUidAccessLocation = checkCallerHasPeersMacAddressPermission(uid);
559         // LocationAccess by App: caller must have Coarse/Fine Location permission to have access to
560         // location information.
561         boolean canAppPackageUseLocation = checkCallersLocationPermission(pkgName, featureId,
562                 uid, /* coarseForTargetSdkLessThanQ */ true, message);
563 
564         // If neither caller or app has location access, there is no need to check
565         // any other permissions. Deny access to scan results.
566         if (!canCallingUidAccessLocation && !canAppPackageUseLocation) {
567             if (mVerboseLoggingEnabled) {
568                 Log.v(TAG, "enforceCanAccessScanResults(pkg=" + pkgName + ", uid=" + uid + "): "
569                         + "canCallingUidAccessLocation=" + canCallingUidAccessLocation
570                         + ", canAppPackageUseLocation=" + canAppPackageUseLocation);
571             }
572             throw new SecurityException("UID " + uid + " has no location permission");
573         }
574         // Check if Wifi Scan request is an operation allowed for this App.
575         if (!isScanAllowedbyApps(pkgName, featureId, uid)) {
576             if (mVerboseLoggingEnabled) {
577                 Log.v(TAG, "enforceCanAccessScanResults(pkg=" + pkgName + ", uid=" + uid + "): "
578                         + "doesn't have app-op " + AppOpsManager.OPSTR_WIFI_SCAN);
579             }
580             throw new SecurityException("UID " + uid + " has no wifi scan permission");
581         }
582         // If the User or profile is current, permission is granted
583         // Otherwise, uid must have INTERACT_ACROSS_USERS_FULL permission.
584         boolean isCurrentProfile = doesUidBelongToUser(
585                 uid, mWifiPermissionsWrapper.getCurrentUser());
586         if (!isCurrentProfile && !checkInteractAcrossUsersFull(uid)) {
587             if (mVerboseLoggingEnabled) {
588                 Log.v(TAG, "enforceCanAccessScanResults(pkg=" + pkgName + ", uid=" + uid + "): "
589                         + "isCurrentProfile=" + isCurrentProfile
590                         + ", checkInteractAcrossUsersFull=" + checkInteractAcrossUsersFull(uid));
591             }
592             throw new SecurityException("UID " + uid + " profile not permitted");
593         }
594     }
595 
596     /**
597      * API to determine if the caller has permissions to get scan results. Throws SecurityException
598      * if the caller has no permission.
599      * @param pkgName package name of the application requesting access
600      * @param featureId The feature in the package
601      * @param uid The uid of the package
602      * @param ignoreLocationSettings Whether this request can bypass location settings.
603      * @param hideFromAppOps Whether to note the request in app-ops logging or not.
604      *
605      * Note: This is to be used for checking permissions in the internal WifiScanner API surface
606      * for requests coming from system apps.
607      */
enforceCanAccessScanResultsForWifiScanner(String pkgName, @Nullable String featureId, int uid, boolean ignoreLocationSettings, boolean hideFromAppOps)608     public void enforceCanAccessScanResultsForWifiScanner(String pkgName,
609             @Nullable String featureId, int uid, boolean ignoreLocationSettings,
610             boolean hideFromAppOps) throws SecurityException {
611         checkPackage(uid, pkgName);
612 
613         // Location mode must be enabled
614         if (!isLocationModeEnabled()) {
615             if (ignoreLocationSettings) {
616                 mLog.w("Request from " + pkgName + " violated location settings");
617             } else {
618                 // Location mode is disabled, scan results cannot be returned
619                 throw new SecurityException("Location mode is disabled for the device");
620             }
621         }
622         // LocationAccess by App: caller must have fine & hardware Location permission to have
623         // access to location information.
624         if (!checkCallersFineLocationPermission(pkgName, featureId, uid, hideFromAppOps,
625                 ignoreLocationSettings) || !checkCallersHardwareLocationPermission(uid)) {
626             throw new SecurityException("UID " + uid + " has no location permission");
627         }
628         // Check if Wifi Scan request is an operation allowed for this App.
629         if (!isScanAllowedbyApps(pkgName, featureId, uid)) {
630             throw new SecurityException("UID " + uid + " has no wifi scan permission");
631         }
632     }
633 
634     /**
635      *
636      * Checks that calling process has android.Manifest.permission.ACCESS_FINE_LOCATION
637      * and a corresponding app op is allowed for this package and uid
638      *
639      * @param pkgName package name of the application requesting access
640      * @param featureId The feature in the package
641      * @param uid The uid of the package
642      * @param needLocationModeEnabled indicates location mode must be enabled.
643      *
644      * @return true if caller has permission, false otherwise
645      */
checkCanAccessWifiDirect(String pkgName, @Nullable String featureId, int uid, boolean needLocationModeEnabled)646     public boolean checkCanAccessWifiDirect(String pkgName, @Nullable String featureId, int uid,
647                                             boolean needLocationModeEnabled) {
648         try {
649             checkPackage(uid, pkgName);
650         } catch (SecurityException se) {
651             Log.e(TAG, "Package check exception - " + se);
652             return false;
653         }
654 
655         // Apps with NETWORK_SETTINGS are granted a bypass.
656         if (checkNetworkSettingsPermission(uid)) {
657             return true;
658         }
659 
660         // Location mode must be enabled if needed.
661         if (needLocationModeEnabled && !isLocationModeEnabled()) {
662             Log.e(TAG, "Location mode is disabled for the device");
663             return false;
664         }
665 
666         // LocationAccess by App: caller must have Fine Location permission to have access to
667         // location information.
668         if (!checkCallersLocationPermission(pkgName, featureId, uid,
669                 /* coarseForTargetSdkLessThanQ */ false, null)) {
670             Log.e(TAG, "UID " + uid + " has no location permission");
671             return false;
672         }
673         return true;
674     }
675 
676     /**
677      * API to validate if a package name belongs to a UID. Throws SecurityException
678      * if pkgName does not belongs to a UID
679      *
680      * @param pkgName package name of the application requesting access
681      * @param uid The uid of the package
682      *
683      */
checkPackage(int uid, String pkgName)684     public void checkPackage(int uid, String pkgName) throws SecurityException {
685         if (pkgName == null) {
686             throw new SecurityException("Checking UID " + uid + " but Package Name is Null");
687         }
688         mAppOps.checkPackage(uid, pkgName);
689     }
690 
691     /**
692      * Returns true if the caller holds PEERS_MAC_ADDRESS permission.
693      */
checkCallerHasPeersMacAddressPermission(int uid)694     private boolean checkCallerHasPeersMacAddressPermission(int uid) {
695         return mWifiPermissionsWrapper.getUidPermission(
696                 android.Manifest.permission.PEERS_MAC_ADDRESS, uid)
697                 == PackageManager.PERMISSION_GRANTED;
698     }
699 
700     /**
701      * Returns true if Wifi scan operation is allowed for this caller
702      * and package.
703      */
isScanAllowedbyApps(String pkgName, @Nullable String featureId, int uid)704     private boolean isScanAllowedbyApps(String pkgName, @Nullable String featureId, int uid) {
705         return noteAppOpAllowed(AppOpsManager.OPSTR_WIFI_SCAN, pkgName, featureId, uid, null);
706     }
707 
708     /**
709      * Returns true if the caller holds INTERACT_ACROSS_USERS_FULL.
710      */
checkInteractAcrossUsersFull(int uid)711     private boolean checkInteractAcrossUsersFull(int uid) {
712         return mWifiPermissionsWrapper.getUidPermission(
713                 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, uid)
714                 == PackageManager.PERMISSION_GRANTED;
715     }
716 
noteAppOpAllowed(String op, String pkgName, @Nullable String featureId, int uid, @Nullable String message)717     private boolean noteAppOpAllowed(String op, String pkgName, @Nullable String featureId,
718             int uid, @Nullable String message) {
719         return mAppOps.noteOp(op, uid, pkgName, featureId, message) == AppOpsManager.MODE_ALLOWED;
720     }
721 
checkAppOpAllowed(String op, String pkgName, int uid)722     private boolean checkAppOpAllowed(String op, String pkgName, int uid) {
723         return mAppOps.unsafeCheckOp(op, uid, pkgName) == AppOpsManager.MODE_ALLOWED;
724     }
725 
retrieveLocationManagerIfNecessary()726     private boolean retrieveLocationManagerIfNecessary() {
727         // This is going to be accessed by multiple threads.
728         synchronized (mLock) {
729             if (mLocationManager == null) {
730                 mLocationManager =
731                         (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
732             }
733         }
734         return mLocationManager != null;
735     }
736 
737     /**
738      * Retrieves a handle to LocationManager (if not already done) and check if location is enabled.
739      */
isLocationModeEnabled()740     public boolean isLocationModeEnabled() {
741         if (!retrieveLocationManagerIfNecessary()) return false;
742         try {
743             return mLocationManager.isLocationEnabledForUser(UserHandle.of(
744                     mWifiPermissionsWrapper.getCurrentUser()));
745         } catch (Exception e) {
746             Log.e(TAG, "Failure to get location mode via API, falling back to settings", e);
747             return mFrameworkFacade.getIntegerSetting(
748                     mContext, Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF)
749                     == Settings.Secure.LOCATION_MODE_ON;
750         }
751     }
752 
753     /**
754      * Returns true if the |uid| holds REQUEST_COMPANION_PROFILE_AUTOMOTIVE_PROJECTION permission.
755      */
checkRequestCompanionProfileAutomotiveProjectionPermission(int uid)756     public boolean checkRequestCompanionProfileAutomotiveProjectionPermission(int uid) {
757         return mWifiPermissionsWrapper.getUidPermission(
758                 REQUEST_COMPANION_PROFILE_AUTOMOTIVE_PROJECTION, uid)
759                 == PackageManager.PERMISSION_GRANTED;
760     }
761 
762     /**
763      * Returns true if the |uid| holds ENTER_CAR_MODE_PRIORITIZED permission.
764      */
checkEnterCarModePrioritized(int uid)765     public boolean checkEnterCarModePrioritized(int uid) {
766         return mWifiPermissionsWrapper.getUidPermission(ENTER_CAR_MODE_PRIORITIZED, uid)
767                 == PackageManager.PERMISSION_GRANTED;
768     }
769 
770     /**
771      * Returns true if the |uid| holds MANAGE_WIFI_INTERFACES permission.
772      */
checkManageWifiInterfacesPermission(int uid)773     public boolean checkManageWifiInterfacesPermission(int uid) {
774         return mWifiPermissionsWrapper.getUidPermission(
775                 android.Manifest.permission.MANAGE_WIFI_INTERFACES, uid)
776                 == PackageManager.PERMISSION_GRANTED;
777     }
778 
779     /**
780      * Returns true if the |uid| holds MANAGE_WIFI_NETWORK_SELECTION permission.
781      */
checkManageWifiNetworkSelectionPermission(int uid)782     public boolean checkManageWifiNetworkSelectionPermission(int uid) {
783         return mWifiPermissionsWrapper.getUidPermission(
784                 android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION, uid)
785                 == PackageManager.PERMISSION_GRANTED;
786     }
787 
788     /**
789      * Returns true if the |uid| holds NETWORK_SETTINGS permission.
790      */
checkNetworkSettingsPermission(int uid)791     public boolean checkNetworkSettingsPermission(int uid) {
792         return mWifiPermissionsWrapper.getUidPermission(
793                 android.Manifest.permission.NETWORK_SETTINGS, uid)
794                 == PackageManager.PERMISSION_GRANTED;
795     }
796 
797     /**
798      * Returns true if the |uid| holds RADIO_SCAN_WITHOUT_LOCATION permission.
799      */
checkScanWithoutLocationPermission(int uid)800     public boolean checkScanWithoutLocationPermission(int uid) {
801         return mWifiPermissionsWrapper.getUidPermission(
802                 android.Manifest.permission.RADIO_SCAN_WITHOUT_LOCATION, uid)
803                 == PackageManager.PERMISSION_GRANTED;
804     }
805 
806     /**
807      * Returns true if the |uid| holds LOCAL_MAC_ADDRESS permission.
808      */
checkLocalMacAddressPermission(int uid)809     public boolean checkLocalMacAddressPermission(int uid) {
810         return mWifiPermissionsWrapper.getUidPermission(
811                 android.Manifest.permission.LOCAL_MAC_ADDRESS, uid)
812                 == PackageManager.PERMISSION_GRANTED;
813     }
814 
815     /**
816      * Returns true if the |uid| holds NETWORK_SETUP_WIZARD permission.
817      */
checkNetworkSetupWizardPermission(int uid)818     public boolean checkNetworkSetupWizardPermission(int uid) {
819         return mWifiPermissionsWrapper.getUidPermission(
820                 android.Manifest.permission.NETWORK_SETUP_WIZARD, uid)
821                 == PackageManager.PERMISSION_GRANTED;
822     }
823 
824     /**
825      * Returns true if the |uid| holds NETWORK_STACK permission.
826      */
checkNetworkStackPermission(int uid)827     public boolean checkNetworkStackPermission(int uid) {
828         return mWifiPermissionsWrapper.getUidPermission(
829                 android.Manifest.permission.NETWORK_STACK, uid)
830                 == PackageManager.PERMISSION_GRANTED;
831     }
832 
833     /**
834      * Returns true if the |uid| holds MAINLINE_NETWORK_STACK permission.
835      */
checkMainlineNetworkStackPermission(int uid)836     public boolean checkMainlineNetworkStackPermission(int uid) {
837         return mWifiPermissionsWrapper.getUidPermission(
838                 NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, uid)
839                 == PackageManager.PERMISSION_GRANTED;
840     }
841 
842     /**
843      * Returns true if the |uid| holds NETWORK_MANAGED_PROVISIONING permission.
844      */
checkNetworkManagedProvisioningPermission(int uid)845     public boolean checkNetworkManagedProvisioningPermission(int uid) {
846         return mWifiPermissionsWrapper.getUidPermission(
847                 android.Manifest.permission.NETWORK_MANAGED_PROVISIONING, uid)
848                 == PackageManager.PERMISSION_GRANTED;
849     }
850 
851     /**
852      * Returns true if the |uid| holds NETWORK_CARRIER_PROVISIONING permission.
853      */
checkNetworkCarrierProvisioningPermission(int uid)854     public boolean checkNetworkCarrierProvisioningPermission(int uid) {
855         return mWifiPermissionsWrapper.getUidPermission(
856                 android.Manifest.permission.NETWORK_CARRIER_PROVISIONING, uid)
857                 == PackageManager.PERMISSION_GRANTED;
858     }
859 
860     /**
861      * Returns true if the |uid| holds READ_WIFI_CREDENTIAL permission.
862      */
checkReadWifiCredentialPermission(int uid)863     public boolean checkReadWifiCredentialPermission(int uid) {
864         return mWifiPermissionsWrapper.getUidPermission(
865                 android.Manifest.permission.READ_WIFI_CREDENTIAL, uid)
866                 == PackageManager.PERMISSION_GRANTED;
867     }
868 
869     /**
870      * Returns true if the |uid| holds CAMERA permission.
871      */
checkCameraPermission(int uid)872     public boolean checkCameraPermission(int uid) {
873         return mWifiPermissionsWrapper.getUidPermission(
874                 android.Manifest.permission.CAMERA, uid)
875                 == PackageManager.PERMISSION_GRANTED;
876     }
877 
878     /**
879      * Returns true if the |callingUid|/\callingPackage| holds SYSTEM_ALERT_WINDOW permission.
880      */
checkSystemAlertWindowPermission(int callingUid, String callingPackage)881     public boolean checkSystemAlertWindowPermission(int callingUid, String callingPackage) {
882         final int mode = mAppOps.noteOp(AppOpsManager.OPSTR_SYSTEM_ALERT_WINDOW, callingUid,
883                 callingPackage, null, null);
884         if (mode == AppOpsManager.MODE_DEFAULT) {
885             return mWifiPermissionsWrapper.getUidPermission(
886                     Manifest.permission.SYSTEM_ALERT_WINDOW, callingUid)
887                     == PackageManager.PERMISSION_GRANTED;
888         }
889         return mode == AppOpsManager.MODE_ALLOWED;
890     }
891 
892     /**
893      * Returns the DevicePolicyManager from context
894      */
retrieveDevicePolicyManagerFromContext(Context context)895     public static DevicePolicyManager retrieveDevicePolicyManagerFromContext(Context context) {
896         DevicePolicyManager devicePolicyManager =
897                 context.getSystemService(DevicePolicyManager.class);
898         if (devicePolicyManager == null
899                 && context.getPackageManager().hasSystemFeature(
900                 PackageManager.FEATURE_DEVICE_ADMIN)) {
901             Log.w(TAG, "Error retrieving DPM service");
902         }
903         return devicePolicyManager;
904     }
905 
906     @Nullable
createPackageContextAsUser(int uid)907     private Context createPackageContextAsUser(int uid) {
908         Context userContext = null;
909         try {
910             userContext = mContext.createPackageContextAsUser(mContext.getPackageName(), 0,
911                     UserHandle.getUserHandleForUid(uid));
912         } catch (PackageManager.NameNotFoundException e) {
913             Log.e(TAG, "Unknown package name");
914             return null;
915         }
916         if (userContext == null) {
917             Log.e(TAG, "Unable to retrieve user context for " + uid);
918             return null;
919         }
920         return userContext;
921     }
922 
retrieveDevicePolicyManagerFromUserContext(int uid)923     private DevicePolicyManager retrieveDevicePolicyManagerFromUserContext(int uid) {
924         Context userContext = createPackageContextAsUser(uid);
925         if (userContext == null) return null;
926         return retrieveDevicePolicyManagerFromContext(userContext);
927     }
928 
929     @Nullable
getDeviceOwner()930     private Pair<UserHandle, ComponentName> getDeviceOwner() {
931         DevicePolicyManager devicePolicyManager =
932                 retrieveDevicePolicyManagerFromContext(mContext);
933         if (devicePolicyManager == null) return null;
934         long ident = Binder.clearCallingIdentity();
935         UserHandle deviceOwnerUser = null;
936         ComponentName deviceOwnerComponent = null;
937         try {
938             deviceOwnerUser = devicePolicyManager.getDeviceOwnerUser();
939             deviceOwnerComponent = devicePolicyManager.getDeviceOwnerComponentOnAnyUser();
940         } finally {
941             Binder.restoreCallingIdentity(ident);
942         }
943         if (deviceOwnerUser == null || deviceOwnerComponent == null) return null;
944 
945         if (deviceOwnerComponent.getPackageName() == null) {
946             // shouldn't happen
947             Log.wtf(TAG, "no package name on device owner component: " + deviceOwnerComponent);
948             return null;
949         }
950         return new Pair<>(deviceOwnerUser, deviceOwnerComponent);
951     }
952 
953     /**
954      * Returns {@code true} if the calling {@code uid} and {@code packageName} is the device owner.
955      */
isDeviceOwner(int uid, @Nullable String packageName)956     public boolean isDeviceOwner(int uid, @Nullable String packageName) {
957         // Cannot determine if the app is DO/PO if packageName is null. So, will return false to be
958         // safe.
959         if (packageName == null) {
960             Log.e(TAG, "isDeviceOwner: packageName is null, returning false");
961             return false;
962         }
963         Pair<UserHandle, ComponentName> deviceOwner = getDeviceOwner();
964         if (mVerboseLoggingEnabled) Log.v(TAG, "deviceOwner:" + deviceOwner);
965 
966         // no device owner
967         if (deviceOwner == null) return false;
968 
969         return deviceOwner.first.equals(UserHandle.getUserHandleForUid(uid))
970                 && deviceOwner.second.getPackageName().equals(packageName);
971     }
972 
973     /**
974      * Returns {@code true} if the calling {@code uid} is the device owner.
975      */
isDeviceOwner(int uid)976     public boolean isDeviceOwner(int uid) {
977         Pair<UserHandle, ComponentName> deviceOwner = getDeviceOwner();
978 
979         // no device owner
980         if (deviceOwner == null) return false;
981 
982         // device owner belowngs to wrong user
983         if (!deviceOwner.first.equals(UserHandle.getUserHandleForUid(uid))) return false;
984 
985         // finally, check uid
986         String deviceOwnerPackageName = deviceOwner.second.getPackageName();
987         String[] packageNames = mContext.getPackageManager().getPackagesForUid(uid);
988         if (mVerboseLoggingEnabled) {
989             Log.v(TAG, "Packages for uid " + uid + ":" + Arrays.toString(packageNames));
990         }
991         if (packageNames == null) {
992             Log.w(TAG, "isDeviceOwner(): could not find packages for packageName="
993                     + deviceOwnerPackageName + " uid=" + uid);
994             return false;
995         }
996         for (String packageName : packageNames) {
997             if (deviceOwnerPackageName.equals(packageName)) return true;
998         }
999 
1000         return false;
1001     }
1002 
1003     /**
1004      * Returns {@code true} if the calling {@code uid} is the OEM privileged admin.
1005      *
1006      * The admin must be allowlisted in the wifi overlay and signed with system cert.
1007      */
1008     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
isOemPrivilegedAdmin(int uid)1009     public boolean isOemPrivilegedAdmin(int uid) {
1010         synchronized (mOemPrivilegedAdminUidCache) {
1011             int cacheIdx = mOemPrivilegedAdminUidCache.indexOfKey(uid);
1012             if (cacheIdx >= 0) {
1013                 return mOemPrivilegedAdminUidCache.valueAt(cacheIdx);
1014             }
1015         }
1016 
1017         boolean result = isOemPrivilegedAdminNoCache(uid);
1018 
1019         synchronized (mOemPrivilegedAdminUidCache) {
1020             mOemPrivilegedAdminUidCache.put(uid, result);
1021         }
1022 
1023         return result;
1024     }
1025 
1026     /**
1027      * Returns {@code true} if the calling {@code uid} is the OEM privileged admin.
1028      *
1029      * This method doesn't memoize results, use {@code isOemPrivilegedAdmin} instead.
1030      */
1031     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
isOemPrivilegedAdminNoCache(int uid)1032     private boolean isOemPrivilegedAdminNoCache(int uid) {
1033         Set<String> oemPrivilegedAdmins = new ArraySet<>(mContext.getResources()
1034                 .getStringArray(R.array.config_oemPrivilegedWifiAdminPackages));
1035         PackageManager pm = mContext.getPackageManager();
1036         String[] packages = pm.getPackagesForUid(uid);
1037         if (packages == null || Arrays.stream(packages).noneMatch(oemPrivilegedAdmins::contains)) {
1038             return false;
1039         }
1040 
1041         return pm.checkSignatures(uid, Process.SYSTEM_UID) == PackageManager.SIGNATURE_MATCH;
1042     }
1043 
1044     /**
1045      * Returns true if the |callingUid|/|callingPackage| is the profile owner.
1046      */
isProfileOwner(int uid, @Nullable String packageName)1047     public boolean isProfileOwner(int uid, @Nullable String packageName) {
1048         // Cannot determine if the app is DO/PO if packageName is null. So, will return false to be
1049         // safe.
1050         if (packageName == null) {
1051             Log.e(TAG, "isProfileOwner: packageName is null, returning false");
1052             return false;
1053         }
1054         DevicePolicyManager devicePolicyManager =
1055                 retrieveDevicePolicyManagerFromUserContext(uid);
1056         if (devicePolicyManager == null) return false;
1057         return devicePolicyManager.isProfileOwnerApp(packageName);
1058     }
1059 
1060     /**
1061      * Returns {@code true} if the calling {@code uid} is the profile owner of
1062      * an organization owned device.
1063      */
isProfileOwnerOfOrganizationOwnedDevice(int uid)1064     public boolean isProfileOwnerOfOrganizationOwnedDevice(int uid) {
1065         DevicePolicyManager devicePolicyManager =
1066                 retrieveDevicePolicyManagerFromUserContext(uid);
1067         if (devicePolicyManager == null) return false;
1068 
1069         // this relies on having only one PO on COPE device.
1070         if (!devicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile()) {
1071             return false;
1072         }
1073         String[] packages = mContext.getPackageManager().getPackagesForUid(uid);
1074         if (packages == null) {
1075             Log.w(TAG, "isProfileOwnerOfOrganizationOwnedDevice(): could not find packages for uid="
1076                     + uid);
1077             return false;
1078         }
1079         for (String packageName : packages) {
1080             if (devicePolicyManager.isProfileOwnerApp(packageName)) return true;
1081         }
1082         return false;
1083     }
1084 
1085     /**
1086      * Returns {@code true} if the calling {@code uid} and {@code packageName} is the device owner
1087      * or the profile owner of an organization owned device.
1088      */
isOrganizationOwnedDeviceAdmin(int uid, @Nullable String packageName)1089     public boolean isOrganizationOwnedDeviceAdmin(int uid, @Nullable String packageName) {
1090         boolean isDeviceOwner =
1091                 packageName == null ? isDeviceOwner(uid) : isDeviceOwner(uid, packageName);
1092         return isDeviceOwner || isProfileOwnerOfOrganizationOwnedDevice(uid);
1093     }
1094 
1095     /** Helper method to check if the entity initiating the binder call is a system app. */
isSystem(String packageName, int uid)1096     public boolean isSystem(String packageName, int uid) {
1097         long ident = Binder.clearCallingIdentity();
1098         try {
1099             ApplicationInfo info = mContext.getPackageManager().getApplicationInfoAsUser(
1100                     packageName, 0, UserHandle.getUserHandleForUid(uid));
1101             return (info.flags & APP_INFO_FLAGS_SYSTEM_APP) != 0;
1102         } catch (PackageManager.NameNotFoundException e) {
1103             // In case of exception, assume unknown app (more strict checking)
1104             // Note: This case will never happen since checkPackage is
1105             // called to verify validity before checking App's version.
1106         } finally {
1107             Binder.restoreCallingIdentity(ident);
1108         }
1109         return false;
1110     }
1111 
1112     /**
1113      * Checks if the given UID belongs to the current foreground or device owner user. This is
1114      * used to prevent apps running in background users from modifying network
1115      * configurations.
1116      * <p>
1117      * UIDs belonging to system internals (such as SystemUI) are always allowed,
1118      * since they always run as {@link UserHandle#USER_SYSTEM}.
1119      *
1120      * @param uid uid of the app.
1121      * @return true if the given UID belongs to the current foreground user,
1122      *         otherwise false.
1123      */
doesUidBelongToCurrentUserOrDeviceOwner(int uid)1124     public boolean doesUidBelongToCurrentUserOrDeviceOwner(int uid) {
1125         boolean isCurrentProfile = doesUidBelongToUser(
1126                 uid, mWifiPermissionsWrapper.getCurrentUser());
1127         if (!isCurrentProfile) {
1128             // Fix for b/174749461
1129             EventLog.writeEvent(0x534e4554, "174749461", -1,
1130                     "Non foreground user trying to modify wifi configuration");
1131         }
1132         return isCurrentProfile || isDeviceOwner(uid);
1133     }
1134 
1135     /**
1136      * Check if the current user is a guest user
1137      * @return true if the current user is a guest user, false otherwise.
1138      */
isGuestUser()1139     public boolean isGuestUser() {
1140         UserManager userManager = mContext.createContextAsUser(
1141                 UserHandle.of(mWifiPermissionsWrapper.getCurrentUser()), 0)
1142                 .getSystemService(UserManager.class);
1143         if (userManager == null) {
1144             return true;
1145         }
1146         return userManager.isGuestUser();
1147     }
1148 
1149     /**
1150      * Checks if the given UID belongs to the given user ID. This is
1151      * used to prevent apps running in other users from modifying network configurations belonging
1152      * to the given user.
1153      * <p>
1154      * UIDs belonging to system internals (such as SystemUI) are always allowed,
1155      * since they always run as {@link UserHandle#USER_SYSTEM}.
1156      *
1157      * @param uid uid to check
1158      * @param userId user to check against
1159      * @return true if the given UID belongs to the given user.
1160      */
doesUidBelongToUser(int uid, int userId)1161     public boolean doesUidBelongToUser(int uid, int userId) {
1162         if (UserHandle.getAppId(uid) == android.os.Process.SYSTEM_UID
1163                 // UIDs with the NETWORK_SETTINGS permission are always allowed since they are
1164                 // acting on behalf of the user.
1165                 || checkNetworkSettingsPermission(uid)) {
1166             return true;
1167         }
1168         UserHandle uidHandle = UserHandle.getUserHandleForUid(uid);
1169         UserHandle userHandle = UserHandle.of(userId);
1170         return uidHandle.equals(userHandle)
1171                 || mUserManager.isSameProfileGroup(uidHandle, userHandle);
1172     }
1173 
1174     /**
1175      * Sets the verbose logging level.
1176      */
enableVerboseLogging(boolean enabled)1177     public void enableVerboseLogging(boolean enabled) {
1178         mVerboseLoggingEnabled = enabled;
1179     }
1180 
1181     /**
1182      * Returns true if the |callingUid|/|callingPackage| is an admin.
1183      */
isAdmin(int uid, @Nullable String packageName)1184     public boolean isAdmin(int uid, @Nullable String packageName) {
1185         // Cannot determine if the app is an admin if packageName is null.
1186         // So, will return false to be safe.
1187         if (packageName == null) {
1188             Log.e(TAG, "isAdmin: packageName is null, returning false");
1189             return false;
1190         }
1191         boolean isOemPrivilegedAdmin = (SdkLevel.isAtLeastT()) ? isOemPrivilegedAdmin(uid) : false;
1192 
1193         return isDeviceOwner(uid, packageName) || isProfileOwner(uid, packageName)
1194                 || isOemPrivilegedAdmin;
1195     }
1196 
1197     /**
1198      * Returns true if the device may not connect to the configuration due to admin restriction
1199      */
isAdminRestrictedNetwork(@ullable WifiConfiguration config)1200     public boolean isAdminRestrictedNetwork(@Nullable WifiConfiguration config) {
1201         if (config == null || !SdkLevel.isAtLeastT()) {
1202             return false;
1203         }
1204 
1205         DevicePolicyManager devicePolicyManager =
1206                 WifiPermissionsUtil.retrieveDevicePolicyManagerFromContext(mContext);
1207         if (devicePolicyManager == null) return false;
1208 
1209         int adminMinimumSecurityLevel = 0;
1210         WifiSsidPolicy policy;
1211         long ident = Binder.clearCallingIdentity();
1212         try {
1213             adminMinimumSecurityLevel = devicePolicyManager.getMinimumRequiredWifiSecurityLevel();
1214             policy = devicePolicyManager.getWifiSsidPolicy();
1215         } finally {
1216             Binder.restoreCallingIdentity(ident);
1217         }
1218 
1219         //check minimum security level restriction
1220         if (adminMinimumSecurityLevel != 0) {
1221             boolean securityRestrictionPassed = false;
1222             for (SecurityParams params : config.getSecurityParamsList()) {
1223                 int securityLevel = WifiInfo.convertSecurityTypeToDpmWifiSecurity(
1224                         WifiInfo.convertWifiConfigurationSecurityType(params.getSecurityType()));
1225 
1226                 // Skip unknown security type since security level cannot be determined.
1227                 if (securityLevel == WifiInfo.DPM_SECURITY_TYPE_UNKNOWN) continue;
1228 
1229                 if (adminMinimumSecurityLevel <= securityLevel) {
1230                     securityRestrictionPassed = true;
1231                     break;
1232                 }
1233             }
1234             if (!securityRestrictionPassed) {
1235                 return true;
1236             }
1237         }
1238 
1239         //check SSID restriction
1240         if (policy != null) {
1241             //skip SSID restriction check for Osu and Passpoint networks
1242             if (config.osu || config.isPasspoint()) return false;
1243 
1244             int policyType = policy.getPolicyType();
1245             Set<WifiSsid> ssids = policy.getSsids();
1246             WifiSsid ssid = WifiSsid.fromString(config.SSID);
1247 
1248             if (policyType == WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_ALLOWLIST
1249                     && !ssids.contains(ssid)) {
1250                 return true;
1251             }
1252             if (policyType == WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_DENYLIST
1253                     && ssids.contains(ssid)) {
1254                 return true;
1255             }
1256         }
1257         return false;
1258     }
1259 
1260     /**
1261      * Returns the foreground userId
1262      */
getCurrentUser()1263     public int getCurrentUser() {
1264         //set the default to undefined user id (UserHandle.USER_NULL)
1265         int user = -10000;
1266         long ident = Binder.clearCallingIdentity();
1267         try {
1268             user = mWifiPermissionsWrapper.getCurrentUser();
1269         } finally {
1270             Binder.restoreCallingIdentity(ident);
1271         }
1272         return user;
1273     }
1274 }
1275