• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 SYSTEM_AUTHORITY_PREFIX = "system:";
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_SYSTEM_ENTITY = "system-entity";
66     private static final String ATTR_CLASS_NAME = "class-name";
67     private static final String ATTR_AUTHORITIES = "authorities";
68     private static final String ATTR_AUTHORITIES_SEPARATOR = ";";
69     private static final String ATTR_USER_ID = "user-id";
70     private static final String ATTR_IS_ROLE = "is-role";
71     private static final String ATTR_IS_SYSTEM = "is-system";
72 
73     private final String mPackageName;
74     // Name of the system entity. Only used when mIsSystemAuthority is true.
75     private final String mSystemEntity;
76     // This is needed for DPCs and active admins
77     private final ComponentName mComponentName;
78     private Set<String> mAuthorities;
79     private final int mUserId;
80     private final boolean mIsRoleAuthority;
81     private final boolean mIsSystemAuthority;
82 
createEnforcingAdmin(@onNull String packageName, int userId)83     static EnforcingAdmin createEnforcingAdmin(@NonNull String packageName, int userId) {
84         Objects.requireNonNull(packageName);
85         return new EnforcingAdmin(packageName, userId);
86     }
87 
createEnterpriseEnforcingAdmin( @onNull ComponentName componentName, int userId)88     static EnforcingAdmin createEnterpriseEnforcingAdmin(
89             @NonNull ComponentName componentName, int userId) {
90         Objects.requireNonNull(componentName);
91         return new EnforcingAdmin(
92                 componentName.getPackageName(), componentName, Set.of(DPC_AUTHORITY), userId);
93     }
94 
createDeviceAdminEnforcingAdmin(ComponentName componentName, int userId)95     static EnforcingAdmin createDeviceAdminEnforcingAdmin(ComponentName componentName, int userId) {
96         Objects.requireNonNull(componentName);
97         return new EnforcingAdmin(
98                 componentName.getPackageName(), componentName, Set.of(DEVICE_ADMIN_AUTHORITY),
99                 userId);
100     }
101 
createSystemEnforcingAdmin(@onNull String systemEntity)102     static EnforcingAdmin createSystemEnforcingAdmin(@NonNull String systemEntity) {
103         Objects.requireNonNull(systemEntity);
104         return new EnforcingAdmin(systemEntity);
105     }
106 
createEnforcingAdmin(android.app.admin.EnforcingAdmin admin)107     static EnforcingAdmin createEnforcingAdmin(android.app.admin.EnforcingAdmin admin) {
108         Objects.requireNonNull(admin);
109         Authority authority = admin.getAuthority();
110         Set<String> internalAuthorities = new HashSet<>();
111         if (DpcAuthority.DPC_AUTHORITY.equals(authority)) {
112             return new EnforcingAdmin(
113                     admin.getPackageName(), admin.getComponentName(),
114                     Set.of(DPC_AUTHORITY), admin.getUserHandle().getIdentifier());
115         } else if (DeviceAdminAuthority.DEVICE_ADMIN_AUTHORITY.equals(authority)) {
116             return new EnforcingAdmin(
117                     admin.getPackageName(), admin.getComponentName(),
118                     Set.of(DEVICE_ADMIN_AUTHORITY), admin.getUserHandle().getIdentifier());
119         } else if (authority instanceof RoleAuthority roleAuthority) {
120             return new EnforcingAdmin(
121                     admin.getPackageName(), admin.getComponentName(),
122                     Set.of(DEVICE_ADMIN_AUTHORITY), admin.getUserHandle().getIdentifier(),
123                     /* isRoleAuthority = */ true);
124         }
125         // TODO(b/324899199): Consider supporting android.app.admin.SystemAuthority.
126         return new EnforcingAdmin(admin.getPackageName(), admin.getComponentName(),
127                 Set.of(), admin.getUserHandle().getIdentifier());
128     }
129 
getRoleAuthorityOf(String roleName)130     static String getRoleAuthorityOf(String roleName) {
131         return ROLE_AUTHORITY_PREFIX + roleName;
132     }
133 
getParcelableAuthority(String authority)134     static Authority getParcelableAuthority(String authority) {
135         if (authority == null || authority.isEmpty()) {
136             return UnknownAuthority.UNKNOWN_AUTHORITY;
137         }
138         if (DPC_AUTHORITY.equals(authority)) {
139             return DpcAuthority.DPC_AUTHORITY;
140         }
141         if (DEVICE_ADMIN_AUTHORITY.equals(authority)) {
142             return DeviceAdminAuthority.DEVICE_ADMIN_AUTHORITY;
143         }
144         if (authority.startsWith(ROLE_AUTHORITY_PREFIX)) {
145             String role = authority.substring(ROLE_AUTHORITY_PREFIX.length());
146             return new RoleAuthority(Set.of(role));
147         }
148         return UnknownAuthority.UNKNOWN_AUTHORITY;
149     }
150 
EnforcingAdmin( String packageName, @Nullable ComponentName componentName, Set<String> authorities, int userId)151     private EnforcingAdmin(
152             String packageName, @Nullable ComponentName componentName, Set<String> authorities,
153             int userId) {
154         Objects.requireNonNull(packageName);
155         Objects.requireNonNull(authorities);
156 
157         // Role/System authorities should not be using this constructor
158         mIsRoleAuthority = false;
159         mIsSystemAuthority = false;
160         mPackageName = packageName;
161         mSystemEntity = null;
162         mComponentName = componentName;
163         mAuthorities = new HashSet<>(authorities);
164         mUserId = userId;
165     }
166 
EnforcingAdmin(String packageName, int userId)167     private EnforcingAdmin(String packageName, int userId) {
168         Objects.requireNonNull(packageName);
169 
170         // Only role authorities use this constructor.
171         mIsRoleAuthority = true;
172         mIsSystemAuthority = false;
173         mPackageName = packageName;
174         mSystemEntity = null;
175         mUserId = userId;
176         mComponentName = null;
177         // authorities will be loaded when needed
178         mAuthorities = null;
179     }
180 
181     /** Constructor for System authorities. */
EnforcingAdmin(@onNull String systemEntity)182     private EnforcingAdmin(@NonNull String systemEntity) {
183         Objects.requireNonNull(systemEntity);
184 
185         // Only system authorities use this constructor.
186         mIsSystemAuthority = true;
187         mIsRoleAuthority = false;
188         // Package name is not used for a system enforcing admin, so an empty string is fine.
189         mPackageName = "";
190         mSystemEntity = systemEntity;
191         mUserId = UserHandle.USER_SYSTEM;
192         mComponentName = null;
193         mAuthorities = getSystemAuthority(systemEntity);
194     }
195 
EnforcingAdmin( String packageName, @Nullable ComponentName componentName, Set<String> authorities, int userId, boolean isRoleAuthority)196     private EnforcingAdmin(
197             String packageName, @Nullable ComponentName componentName, Set<String> authorities,
198             int userId, boolean isRoleAuthority) {
199         Objects.requireNonNull(packageName);
200         Objects.requireNonNull(authorities);
201 
202         mIsRoleAuthority = isRoleAuthority;
203         mIsSystemAuthority = false;
204         mPackageName = packageName;
205         mSystemEntity = null;
206         mComponentName = componentName;
207         mAuthorities = new HashSet<>(authorities);
208         mUserId = userId;
209     }
210 
getRoleAuthoritiesOrDefault(String packageName, int userId)211     private static Set<String> getRoleAuthoritiesOrDefault(String packageName, int userId) {
212         Set<String> roles = getRoles(packageName, userId);
213         Set<String> authorities = new HashSet<>();
214         for (String role : roles) {
215             authorities.add(ROLE_AUTHORITY_PREFIX + role);
216         }
217         return authorities.isEmpty() ? Set.of(DEFAULT_AUTHORITY) : authorities;
218     }
219 
220     /**
221      * Returns a set of authorities for system authority.
222      *
223      * <p>Note that a system authority enforcing admin has only one authority that has the package
224      * name of the calling system service. Therefore, the returned set always contains one element.
225      */
getSystemAuthority(String systemEntity)226     private static Set<String> getSystemAuthority(String systemEntity) {
227         Set<String> authorities = new HashSet<>();
228         authorities.add(SYSTEM_AUTHORITY_PREFIX + systemEntity);
229         return authorities;
230     }
231 
232     // TODO(b/259042794): move this logic to RoleManagerLocal
getRoles(String packageName, int userId)233     private static Set<String> getRoles(String packageName, int userId) {
234         RoleManagerLocal roleManagerLocal = LocalManagerRegistry.getManager(
235                 RoleManagerLocal.class);
236         Set<String> roles = new HashSet<>();
237         Map<String, Set<String>> rolesAndHolders = roleManagerLocal.getRolesAndHolders(userId);
238         for (String role : rolesAndHolders.keySet()) {
239             if (rolesAndHolders.get(role).contains(packageName)) {
240                 roles.add(role);
241             }
242         }
243         return roles;
244     }
245 
getAuthorities()246     private Set<String> getAuthorities() {
247         if (mAuthorities == null && mIsRoleAuthority) {
248             mAuthorities = getRoleAuthoritiesOrDefault(mPackageName, mUserId);
249         }
250         return mAuthorities;
251     }
252 
reloadRoleAuthorities()253     void reloadRoleAuthorities() {
254         if (mIsRoleAuthority) {
255             mAuthorities = getRoleAuthoritiesOrDefault(mPackageName, mUserId);
256         }
257     }
258 
hasAuthority(String authority)259     boolean hasAuthority(String authority) {
260         return getAuthorities().contains(authority);
261     }
262 
isSystemAuthority()263     boolean isSystemAuthority() {
264         return mIsSystemAuthority;
265     }
266 
267     @NonNull
getPackageName()268     String getPackageName() {
269         return mPackageName;
270     }
271 
getUserId()272     int getUserId() {
273         return mUserId;
274     }
275 
276     @Nullable
getComponentName()277     ComponentName getComponentName() {
278         return mComponentName;
279     }
280 
281     @NonNull
getParcelableAdmin()282     android.app.admin.EnforcingAdmin getParcelableAdmin() {
283         Authority authority;
284         if (mIsRoleAuthority) {
285             Set<String> roles = getRoles(mPackageName, mUserId);
286             if (roles.isEmpty()) {
287                 authority = UnknownAuthority.UNKNOWN_AUTHORITY;
288             } else {
289                 authority = new RoleAuthority(roles);
290             }
291         } else if (mAuthorities.contains(DPC_AUTHORITY)) {
292             authority = DpcAuthority.DPC_AUTHORITY;
293         } else if (mAuthorities.contains(DEVICE_ADMIN_AUTHORITY)) {
294             authority = DeviceAdminAuthority.DEVICE_ADMIN_AUTHORITY;
295         } else if (mIsSystemAuthority) {
296             // For now, System Authority returns UnknownAuthority.
297             authority = new UnknownAuthority(mSystemEntity);
298         } else {
299             authority = UnknownAuthority.UNKNOWN_AUTHORITY;
300         }
301         return new android.app.admin.EnforcingAdmin(
302                 mPackageName,
303                 authority,
304                 UserHandle.of(mUserId),
305                 mComponentName);
306     }
307 
308     /**
309      * For two EnforcingAdmins to be equal they must:
310      *
311      * <ul>
312      *     <li> have the same package names and component names and either
313      *     <li> have exactly the same authorities ({@link #DPC_AUTHORITY} or
314      *     {@link #DEVICE_ADMIN_AUTHORITY}), or have any role or default authorities.
315      * </ul>
316      *
317      * <p>EnforcingAdmins are considered equal if they have any role authority as they can have
318      * roles granted/revoked between calls.
319      */
320     @Override
equals(@ullable Object o)321     public boolean equals(@Nullable Object o) {
322         if (this == o) return true;
323         if (o == null || getClass() != o.getClass()) return false;
324         EnforcingAdmin other = (EnforcingAdmin) o;
325         return Objects.equals(mPackageName, other.mPackageName)
326                 && Objects.equals(mSystemEntity, other.mSystemEntity)
327                 && Objects.equals(mComponentName, other.mComponentName)
328                 && Objects.equals(mIsRoleAuthority, other.mIsRoleAuthority)
329                 && (mIsSystemAuthority == other.mIsSystemAuthority)
330                 && hasMatchingAuthorities(this, other);
331     }
332 
hasMatchingAuthorities(EnforcingAdmin admin1, EnforcingAdmin admin2)333     private static boolean hasMatchingAuthorities(EnforcingAdmin admin1, EnforcingAdmin admin2) {
334         if (admin1.mIsRoleAuthority && admin2.mIsRoleAuthority) {
335             return true;
336         }
337         return admin1.getAuthorities().equals(admin2.getAuthorities());
338     }
339 
340     @Override
hashCode()341     public int hashCode() {
342         if (mIsRoleAuthority) {
343             return Objects.hash(mPackageName, mUserId);
344         } else if (mIsSystemAuthority) {
345             return Objects.hash(mSystemEntity);
346         } else {
347             return Objects.hash(
348                     mComponentName == null ? mPackageName : mComponentName,
349                     mUserId,
350                     getAuthorities());
351         }
352     }
353 
saveToXml(TypedXmlSerializer serializer)354     void saveToXml(TypedXmlSerializer serializer) throws IOException {
355         serializer.attribute(/* namespace= */ null, ATTR_PACKAGE_NAME, mPackageName);
356         serializer.attributeBoolean(/* namespace= */ null, ATTR_IS_ROLE, mIsRoleAuthority);
357         serializer.attributeBoolean(/* namespace= */ null, ATTR_IS_SYSTEM, mIsSystemAuthority);
358         serializer.attributeInt(/* namespace= */ null, ATTR_USER_ID, mUserId);
359         if (mIsSystemAuthority) {
360             serializer.attribute(/* namespace= */ null, ATTR_SYSTEM_ENTITY, mSystemEntity);
361         }
362         if (!mIsRoleAuthority && !mIsSystemAuthority) {
363             if (mComponentName != null) {
364                 serializer.attribute(
365                         /* namespace= */ null, ATTR_CLASS_NAME, mComponentName.getClassName());
366             }
367             // Role authorities get recomputed on load so no need to save them.
368             serializer.attribute(
369                     /* namespace= */ null,
370                     ATTR_AUTHORITIES,
371                     String.join(ATTR_AUTHORITIES_SEPARATOR, getAuthorities()));
372         }
373     }
374 
375     @Nullable
readFromXml(TypedXmlPullParser parser)376     static EnforcingAdmin readFromXml(TypedXmlPullParser parser)
377             throws XmlPullParserException {
378         String packageName = parser.getAttributeValue(/* namespace= */ null, ATTR_PACKAGE_NAME);
379         String systemEntity = parser.getAttributeValue(/* namespace= */ null, ATTR_SYSTEM_ENTITY);
380         boolean isRoleAuthority = parser.getAttributeBoolean(/* namespace= */ null, ATTR_IS_ROLE);
381         boolean isSystemAuthority = parser.getAttributeBoolean(
382                 /* namespace= */ null, ATTR_IS_SYSTEM, /* defaultValue= */ false);
383         String authoritiesStr = parser.getAttributeValue(/* namespace= */ null, ATTR_AUTHORITIES);
384         int userId = parser.getAttributeInt(/* namespace= */ null, ATTR_USER_ID);
385 
386         if (isRoleAuthority) {
387             if (packageName == null) {
388                 Slogf.wtf(TAG, "Error parsing EnforcingAdmin with RoleAuthority, packageName is "
389                         + "null.");
390                 return null;
391             }
392             // TODO(b/281697976): load active admin
393             return new EnforcingAdmin(packageName, userId);
394         } else if (isSystemAuthority) {
395             if (systemEntity == null) {
396                 Slogf.wtf(TAG, "Error parsing EnforcingAdmin with SystemAuthority, "
397                         + "systemEntity is null.");
398                 return null;
399             }
400             return new EnforcingAdmin(systemEntity);
401         } else {
402             if (packageName == null || authoritiesStr == null) {
403                 Slogf.wtf(TAG, "Error parsing EnforcingAdmin, packageName is "
404                         + (packageName == null ? "null" : packageName) + ", and authorities is "
405                         + (authoritiesStr == null ? "null" : authoritiesStr) + ".");
406                 return null;
407             }
408             String className = parser.getAttributeValue(/* namespace= */ null, ATTR_CLASS_NAME);
409             ComponentName componentName = className == null
410                     ? null :  new ComponentName(packageName, className);
411             Set<String> authorities = Set.of(authoritiesStr.split(ATTR_AUTHORITIES_SEPARATOR));
412             // TODO(b/281697976): load active admin
413             return new EnforcingAdmin(packageName, componentName, authorities, userId);
414         }
415     }
416 
417     @Override
toString()418     public String toString() {
419         StringBuilder sb = new StringBuilder();
420         sb.append("EnforcingAdmin { mPackageName= ");
421         sb.append(mPackageName);
422         if (mComponentName != null) {
423             sb.append(", mComponentName= ");
424             sb.append(mComponentName);
425         }
426         if (mAuthorities != null) {
427             sb.append(", mAuthorities= ");
428             sb.append(mAuthorities);
429         }
430         sb.append(", mUserId= ");
431         sb.append(mUserId);
432         sb.append(", mIsRoleAuthority= ");
433         sb.append(mIsRoleAuthority);
434         sb.append(", mIsSystemAuthority= ");
435         sb.append(mIsSystemAuthority);
436         sb.append(", mSystemEntity = ");
437         sb.append(mSystemEntity);
438         sb.append(" }");
439         return sb.toString();
440     }
441 }
442