1 /* 2 * Copyright (C) 2022 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.devicepolicy; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.app.admin.Authority; 22 import android.app.admin.DeviceAdminAuthority; 23 import android.app.admin.DpcAuthority; 24 import android.app.admin.PackagePermissionPolicyKey; 25 import android.app.admin.RoleAuthority; 26 import android.app.admin.UnknownAuthority; 27 import android.content.ComponentName; 28 import android.os.UserHandle; 29 30 import com.android.modules.utils.TypedXmlPullParser; 31 import com.android.modules.utils.TypedXmlSerializer; 32 import com.android.role.RoleManagerLocal; 33 import com.android.server.LocalManagerRegistry; 34 import com.android.server.utils.Slogf; 35 36 import org.xmlpull.v1.XmlPullParserException; 37 38 import java.io.IOException; 39 import java.util.HashSet; 40 import java.util.Map; 41 import java.util.Objects; 42 import java.util.Set; 43 44 /** 45 * {@code EnforcingAdmins} can have the following authority types: 46 * 47 * <ul> 48 * <li> {@link #DPC_AUTHORITY} meaning it's an enterprise admin (e.g. PO, DO, COPE) 49 * <li> {@link #DEVICE_ADMIN_AUTHORITY} which is a legacy non enterprise admin 50 * <li> Or a role authority, in which case {@link #mAuthorities} contains a list of all roles 51 * held by the given {@code packageName} 52 * </ul> 53 * 54 */ 55 final class EnforcingAdmin { 56 57 static final String TAG = "EnforcingAdmin"; 58 59 static final String ROLE_AUTHORITY_PREFIX = "role:"; 60 static final String DPC_AUTHORITY = "enterprise"; 61 static final String DEVICE_ADMIN_AUTHORITY = "device_admin"; 62 static final String DEFAULT_AUTHORITY = "default"; 63 64 private static final String ATTR_PACKAGE_NAME = "package-name"; 65 private static final String ATTR_CLASS_NAME = "class-name"; 66 private static final String ATTR_AUTHORITIES = "authorities"; 67 private static final String ATTR_AUTHORITIES_SEPARATOR = ";"; 68 private static final String ATTR_USER_ID = "user-id"; 69 private static final String ATTR_IS_ROLE = "is-role"; 70 71 private final String mPackageName; 72 // This is needed for DPCs and active admins 73 private final ComponentName mComponentName; 74 private Set<String> mAuthorities; 75 private final int mUserId; 76 private final boolean mIsRoleAuthority; 77 private final ActiveAdmin mActiveAdmin; 78 createEnforcingAdmin(@onNull String packageName, int userId, ActiveAdmin admin)79 static EnforcingAdmin createEnforcingAdmin(@NonNull String packageName, int userId, 80 ActiveAdmin admin) { 81 Objects.requireNonNull(packageName); 82 return new EnforcingAdmin(packageName, userId, admin); 83 } 84 createEnterpriseEnforcingAdmin( @onNull ComponentName componentName, int userId)85 static EnforcingAdmin createEnterpriseEnforcingAdmin( 86 @NonNull ComponentName componentName, int userId) { 87 Objects.requireNonNull(componentName); 88 return new EnforcingAdmin( 89 componentName.getPackageName(), componentName, Set.of(DPC_AUTHORITY), userId, 90 /* activeAdmin=*/ null); 91 } 92 createEnterpriseEnforcingAdmin( @onNull ComponentName componentName, int userId, ActiveAdmin activeAdmin)93 static EnforcingAdmin createEnterpriseEnforcingAdmin( 94 @NonNull ComponentName componentName, int userId, ActiveAdmin activeAdmin) { 95 Objects.requireNonNull(componentName); 96 return new EnforcingAdmin( 97 componentName.getPackageName(), componentName, Set.of(DPC_AUTHORITY), userId, 98 activeAdmin); 99 } 100 createDeviceAdminEnforcingAdmin(ComponentName componentName, int userId, ActiveAdmin activeAdmin)101 static EnforcingAdmin createDeviceAdminEnforcingAdmin(ComponentName componentName, int userId, 102 ActiveAdmin activeAdmin) { 103 Objects.requireNonNull(componentName); 104 return new EnforcingAdmin( 105 componentName.getPackageName(), componentName, Set.of(DEVICE_ADMIN_AUTHORITY), 106 userId, activeAdmin); 107 } 108 createEnforcingAdmin(android.app.admin.EnforcingAdmin admin)109 static EnforcingAdmin createEnforcingAdmin(android.app.admin.EnforcingAdmin admin) { 110 Objects.requireNonNull(admin); 111 Authority authority = admin.getAuthority(); 112 Set<String> internalAuthorities = new HashSet<>(); 113 if (DpcAuthority.DPC_AUTHORITY.equals(authority)) { 114 return new EnforcingAdmin( 115 admin.getPackageName(), admin.getComponentName(), 116 Set.of(DPC_AUTHORITY), admin.getUserHandle().getIdentifier(), 117 /* activeAdmin = */ null); 118 } else if (DeviceAdminAuthority.DEVICE_ADMIN_AUTHORITY.equals(authority)) { 119 return new EnforcingAdmin( 120 admin.getPackageName(), admin.getComponentName(), 121 Set.of(DEVICE_ADMIN_AUTHORITY), admin.getUserHandle().getIdentifier(), 122 /* activeAdmin = */ null); 123 } else if (authority instanceof RoleAuthority roleAuthority) { 124 return new EnforcingAdmin( 125 admin.getPackageName(), admin.getComponentName(), 126 Set.of(DEVICE_ADMIN_AUTHORITY), admin.getUserHandle().getIdentifier(), 127 /* activeAdmin = */ null, 128 /* isRoleAuthority = */ true); 129 } 130 return new EnforcingAdmin(admin.getPackageName(), admin.getComponentName(), 131 Set.of(), admin.getUserHandle().getIdentifier(), 132 /* activeAdmin = */ null); 133 } 134 getRoleAuthorityOf(String roleName)135 static String getRoleAuthorityOf(String roleName) { 136 return ROLE_AUTHORITY_PREFIX + roleName; 137 } 138 getParcelableAuthority(String authority)139 static Authority getParcelableAuthority(String authority) { 140 if (authority == null || authority.isEmpty()) { 141 return UnknownAuthority.UNKNOWN_AUTHORITY; 142 } 143 if (DPC_AUTHORITY.equals(authority)) { 144 return DpcAuthority.DPC_AUTHORITY; 145 } 146 if (DEVICE_ADMIN_AUTHORITY.equals(authority)) { 147 return DeviceAdminAuthority.DEVICE_ADMIN_AUTHORITY; 148 } 149 if (authority.startsWith(ROLE_AUTHORITY_PREFIX)) { 150 String role = authority.substring(ROLE_AUTHORITY_PREFIX.length()); 151 return new RoleAuthority(Set.of(role)); 152 } 153 return UnknownAuthority.UNKNOWN_AUTHORITY; 154 } 155 EnforcingAdmin( String packageName, @Nullable ComponentName componentName, Set<String> authorities, int userId, @Nullable ActiveAdmin activeAdmin)156 private EnforcingAdmin( 157 String packageName, @Nullable ComponentName componentName, Set<String> authorities, 158 int userId, @Nullable ActiveAdmin activeAdmin) { 159 Objects.requireNonNull(packageName); 160 Objects.requireNonNull(authorities); 161 162 // Role authorities should not be using this constructor 163 mIsRoleAuthority = false; 164 mPackageName = packageName; 165 mComponentName = componentName; 166 mAuthorities = new HashSet<>(authorities); 167 mUserId = userId; 168 mActiveAdmin = activeAdmin; 169 } 170 EnforcingAdmin(String packageName, int userId, ActiveAdmin activeAdmin)171 private EnforcingAdmin(String packageName, int userId, ActiveAdmin activeAdmin) { 172 Objects.requireNonNull(packageName); 173 174 // Only role authorities use this constructor. 175 mIsRoleAuthority = true; 176 mPackageName = packageName; 177 mUserId = userId; 178 mComponentName = null; 179 // authorities will be loaded when needed 180 mAuthorities = null; 181 mActiveAdmin = activeAdmin; 182 } 183 EnforcingAdmin( String packageName, @Nullable ComponentName componentName, Set<String> authorities, int userId, @Nullable ActiveAdmin activeAdmin, boolean isRoleAuthority)184 private EnforcingAdmin( 185 String packageName, @Nullable ComponentName componentName, Set<String> authorities, 186 int userId, @Nullable ActiveAdmin activeAdmin, boolean isRoleAuthority) { 187 Objects.requireNonNull(packageName); 188 Objects.requireNonNull(authorities); 189 190 mIsRoleAuthority = isRoleAuthority; 191 mPackageName = packageName; 192 mComponentName = componentName; 193 mAuthorities = new HashSet<>(authorities); 194 mUserId = userId; 195 mActiveAdmin = activeAdmin; 196 } 197 getRoleAuthoritiesOrDefault(String packageName, int userId)198 private static Set<String> getRoleAuthoritiesOrDefault(String packageName, int userId) { 199 Set<String> roles = getRoles(packageName, userId); 200 Set<String> authorities = new HashSet<>(); 201 for (String role : roles) { 202 authorities.add(ROLE_AUTHORITY_PREFIX + role); 203 } 204 return authorities.isEmpty() ? Set.of(DEFAULT_AUTHORITY) : authorities; 205 } 206 207 // TODO(b/259042794): move this logic to RoleManagerLocal getRoles(String packageName, int userId)208 private static Set<String> getRoles(String packageName, int userId) { 209 RoleManagerLocal roleManagerLocal = LocalManagerRegistry.getManager( 210 RoleManagerLocal.class); 211 Set<String> roles = new HashSet<>(); 212 Map<String, Set<String>> rolesAndHolders = roleManagerLocal.getRolesAndHolders(userId); 213 for (String role : rolesAndHolders.keySet()) { 214 if (rolesAndHolders.get(role).contains(packageName)) { 215 roles.add(role); 216 } 217 } 218 return roles; 219 } 220 getAuthorities()221 private Set<String> getAuthorities() { 222 if (mAuthorities == null && mIsRoleAuthority) { 223 mAuthorities = getRoleAuthoritiesOrDefault(mPackageName, mUserId); 224 } 225 return mAuthorities; 226 } 227 reloadRoleAuthorities()228 void reloadRoleAuthorities() { 229 if (mIsRoleAuthority) { 230 mAuthorities = getRoleAuthoritiesOrDefault(mPackageName, mUserId); 231 } 232 } 233 hasAuthority(String authority)234 boolean hasAuthority(String authority) { 235 return getAuthorities().contains(authority); 236 } 237 238 @NonNull getPackageName()239 String getPackageName() { 240 return mPackageName; 241 } 242 getUserId()243 int getUserId() { 244 return mUserId; 245 } 246 247 @Nullable getActiveAdmin()248 public ActiveAdmin getActiveAdmin() { 249 return mActiveAdmin; 250 } 251 252 @NonNull getParcelableAdmin()253 android.app.admin.EnforcingAdmin getParcelableAdmin() { 254 Authority authority; 255 if (mIsRoleAuthority) { 256 Set<String> roles = getRoles(mPackageName, mUserId); 257 if (roles.isEmpty()) { 258 authority = UnknownAuthority.UNKNOWN_AUTHORITY; 259 } else { 260 authority = new RoleAuthority(roles); 261 } 262 } else if (mAuthorities.contains(DPC_AUTHORITY)) { 263 authority = DpcAuthority.DPC_AUTHORITY; 264 } else if (mAuthorities.contains(DEVICE_ADMIN_AUTHORITY)) { 265 authority = DeviceAdminAuthority.DEVICE_ADMIN_AUTHORITY; 266 } else { 267 authority = UnknownAuthority.UNKNOWN_AUTHORITY; 268 } 269 return new android.app.admin.EnforcingAdmin( 270 mPackageName, 271 authority, 272 UserHandle.of(mUserId), 273 mComponentName); 274 } 275 276 /** 277 * For two EnforcingAdmins to be equal they must: 278 * 279 * <ul> 280 * <li> have the same package names and component names and either 281 * <li> have exactly the same authorities ({@link #DPC_AUTHORITY} or 282 * {@link #DEVICE_ADMIN_AUTHORITY}), or have any role or default authorities. 283 * </ul> 284 * 285 * <p>EnforcingAdmins are considered equal if they have any role authority as they can have 286 * roles granted/revoked between calls. 287 */ 288 @Override equals(@ullable Object o)289 public boolean equals(@Nullable Object o) { 290 if (this == o) return true; 291 if (o == null || getClass() != o.getClass()) return false; 292 EnforcingAdmin other = (EnforcingAdmin) o; 293 return Objects.equals(mPackageName, other.mPackageName) 294 && Objects.equals(mComponentName, other.mComponentName) 295 && Objects.equals(mIsRoleAuthority, other.mIsRoleAuthority) 296 && hasMatchingAuthorities(this, other); 297 } 298 hasMatchingAuthorities(EnforcingAdmin admin1, EnforcingAdmin admin2)299 private static boolean hasMatchingAuthorities(EnforcingAdmin admin1, EnforcingAdmin admin2) { 300 if (admin1.mIsRoleAuthority && admin2.mIsRoleAuthority) { 301 return true; 302 } 303 return admin1.getAuthorities().equals(admin2.getAuthorities()); 304 } 305 306 @Override hashCode()307 public int hashCode() { 308 if (mIsRoleAuthority) { 309 return Objects.hash(mPackageName, mUserId); 310 } else { 311 return Objects.hash( 312 mComponentName == null ? mPackageName : mComponentName, 313 mUserId, 314 getAuthorities()); 315 } 316 } 317 saveToXml(TypedXmlSerializer serializer)318 void saveToXml(TypedXmlSerializer serializer) throws IOException { 319 serializer.attribute(/* namespace= */ null, ATTR_PACKAGE_NAME, mPackageName); 320 serializer.attributeBoolean(/* namespace= */ null, ATTR_IS_ROLE, mIsRoleAuthority); 321 serializer.attributeInt(/* namespace= */ null, ATTR_USER_ID, mUserId); 322 if (!mIsRoleAuthority) { 323 if (mComponentName != null) { 324 serializer.attribute( 325 /* namespace= */ null, ATTR_CLASS_NAME, mComponentName.getClassName()); 326 } 327 // Role authorities get recomputed on load so no need to save them. 328 serializer.attribute( 329 /* namespace= */ null, 330 ATTR_AUTHORITIES, 331 String.join(ATTR_AUTHORITIES_SEPARATOR, getAuthorities())); 332 } 333 } 334 335 @Nullable readFromXml(TypedXmlPullParser parser)336 static EnforcingAdmin readFromXml(TypedXmlPullParser parser) 337 throws XmlPullParserException { 338 String packageName = parser.getAttributeValue(/* namespace= */ null, ATTR_PACKAGE_NAME); 339 boolean isRoleAuthority = parser.getAttributeBoolean(/* namespace= */ null, ATTR_IS_ROLE); 340 String authoritiesStr = parser.getAttributeValue(/* namespace= */ null, ATTR_AUTHORITIES); 341 int userId = parser.getAttributeInt(/* namespace= */ null, ATTR_USER_ID); 342 343 if (isRoleAuthority) { 344 if (packageName == null) { 345 Slogf.wtf(TAG, "Error parsing EnforcingAdmin with RoleAuthority, packageName is " 346 + "null."); 347 return null; 348 } 349 // TODO(b/281697976): load active admin 350 return new EnforcingAdmin(packageName, userId, null); 351 } else { 352 if (packageName == null || authoritiesStr == null) { 353 Slogf.wtf(TAG, "Error parsing EnforcingAdmin, packageName is " 354 + (packageName == null ? "null" : packageName) + ", and authorities is " 355 + (authoritiesStr == null ? "null" : authoritiesStr) + "."); 356 return null; 357 } 358 String className = parser.getAttributeValue(/* namespace= */ null, ATTR_CLASS_NAME); 359 ComponentName componentName = className == null 360 ? null : new ComponentName(packageName, className); 361 Set<String> authorities = Set.of(authoritiesStr.split(ATTR_AUTHORITIES_SEPARATOR)); 362 // TODO(b/281697976): load active admin 363 return new EnforcingAdmin(packageName, componentName, authorities, userId, null); 364 } 365 } 366 367 @Override toString()368 public String toString() { 369 StringBuilder sb = new StringBuilder(); 370 sb.append("EnforcingAdmin { mPackageName= "); 371 sb.append(mPackageName); 372 if (mComponentName != null) { 373 sb.append(", mComponentName= "); 374 sb.append(mComponentName); 375 } 376 if (mAuthorities != null) { 377 sb.append(", mAuthorities= "); 378 sb.append(mAuthorities); 379 } 380 sb.append(", mUserId= "); 381 sb.append(mUserId); 382 sb.append(", mIsRoleAuthority= "); 383 sb.append(mIsRoleAuthority); 384 sb.append(" }"); 385 return sb.toString(); 386 } 387 } 388