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