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