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