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 package com.android.server.devicepolicy;
17 
18 import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_DEFAULT;
19 
20 import android.annotation.Nullable;
21 import android.app.admin.SystemUpdateInfo;
22 import android.app.admin.SystemUpdatePolicy;
23 import android.content.ComponentName;
24 import android.os.UserHandle;
25 import android.util.ArrayMap;
26 import android.util.AtomicFile;
27 import android.util.IndentingPrintWriter;
28 import android.util.Log;
29 import android.util.Slog;
30 import android.util.Xml;
31 
32 import com.android.internal.annotations.VisibleForTesting;
33 import com.android.modules.utils.TypedXmlPullParser;
34 import com.android.modules.utils.TypedXmlSerializer;
35 
36 import libcore.io.IoUtils;
37 
38 import org.xmlpull.v1.XmlPullParserException;
39 
40 import java.io.File;
41 import java.io.FileOutputStream;
42 import java.io.IOException;
43 import java.io.InputStream;
44 import java.time.LocalDate;
45 import java.util.ArrayList;
46 import java.util.List;
47 import java.util.Map;
48 
49 class OwnersData {
50     private static final String TAG = "DevicePolicyManagerService";
51 
52     private static final boolean DEBUG = false; // DO NOT SUBMIT WITH TRUE
53 
54     // XML storing device owner info, system update policy and pending OTA update information.
55     private static final String DEVICE_OWNER_XML = "device_owner_2.xml";
56     private static final String PROFILE_OWNER_XML = "profile_owner.xml";
57 
58     private static final String TAG_ROOT = "root";
59     private static final String TAG_DEVICE_OWNER = "device-owner";
60     private static final String TAG_SYSTEM_UPDATE_POLICY = "system-update-policy";
61     private static final String TAG_FREEZE_PERIOD_RECORD = "freeze-record";
62     private static final String TAG_PENDING_OTA_INFO = "pending-ota-info";
63     private static final String TAG_PROFILE_OWNER = "profile-owner";
64     // Holds "context" for device-owner, this must not be show up before device-owner.
65     private static final String TAG_DEVICE_OWNER_CONTEXT = "device-owner-context";
66     private static final String TAG_DEVICE_OWNER_TYPE = "device-owner-type";
67     private static final String TAG_DEVICE_OWNER_PROTECTED_PACKAGES =
68             "device-owner-protected-packages";
69     private static final String TAG_POLICY_ENGINE_MIGRATION = "policy-engine-migration";
70 
71     private static final String ATTR_NAME = "name";
72     private static final String ATTR_PACKAGE = "package";
73     private static final String ATTR_COMPONENT_NAME = "component";
74     private static final String ATTR_SIZE = "size";
75     private static final String ATTR_REMOTE_BUGREPORT_URI = "remoteBugreportUri";
76     private static final String ATTR_REMOTE_BUGREPORT_HASH = "remoteBugreportHash";
77     private static final String ATTR_USERID = "userId";
78     private static final String ATTR_FREEZE_RECORD_START = "start";
79     private static final String ATTR_FREEZE_RECORD_END = "end";
80     // Legacy attribute, its presence would mean the profile owner associated with it is
81     // managing a profile on an organization-owned device.
82     private static final String ATTR_CAN_ACCESS_DEVICE_IDS = "canAccessDeviceIds";
83     // New attribute for profile owner of organization-owned device.
84     private static final String ATTR_PROFILE_OWNER_OF_ORG_OWNED_DEVICE =
85             "isPoOrganizationOwnedDevice";
86     private static final String ATTR_DEVICE_OWNER_TYPE_VALUE = "value";
87 
88     private static final String ATTR_MIGRATED_TO_POLICY_ENGINE = "migratedToPolicyEngine";
89 
90     // Internal state for the device owner package.
91     OwnerInfo mDeviceOwner;
92     int mDeviceOwnerUserId = UserHandle.USER_NULL;
93 
94     // Device owner type for a managed device.
95     final ArrayMap<String, Integer> mDeviceOwnerTypes = new ArrayMap<>();
96 
97     /** @deprecated moved to {@link ActiveAdmin#protectedPackages}. */
98     @Deprecated
99     @Nullable
100     ArrayMap<String, List<String>> mDeviceOwnerProtectedPackages;
101 
102     // Internal state for the profile owner packages.
103     final ArrayMap<Integer, OwnerInfo> mProfileOwners = new ArrayMap<>();
104 
105     // Local system update policy controllable by device owner.
106     SystemUpdatePolicy mSystemUpdatePolicy;
107     LocalDate mSystemUpdateFreezeStart;
108     LocalDate mSystemUpdateFreezeEnd;
109 
110     // Pending OTA info if there is one.
111     @Nullable
112     SystemUpdateInfo mSystemUpdateInfo;
113     private final PolicyPathProvider mPathProvider;
114 
115     boolean mMigratedToPolicyEngine = false;
116 
OwnersData(PolicyPathProvider pathProvider)117     OwnersData(PolicyPathProvider pathProvider) {
118         mPathProvider = pathProvider;
119     }
120 
load(int[] allUsers)121     void load(int[] allUsers) {
122         new DeviceOwnerReadWriter().readFromFileLocked();
123 
124         for (int userId : allUsers) {
125             new ProfileOwnerReadWriter(userId).readFromFileLocked();
126         }
127 
128         OwnerInfo profileOwner = mProfileOwners.get(mDeviceOwnerUserId);
129         ComponentName admin = profileOwner != null ? profileOwner.admin : null;
130         if (mDeviceOwner != null && admin != null) {
131             Slog.w(TAG, String.format("User %d has both DO and PO, which is not supported",
132                     mDeviceOwnerUserId));
133         }
134     }
135 
136     /**
137      * @return true upon success, false otherwise.
138      */
writeDeviceOwner()139     boolean writeDeviceOwner() {
140         if (DEBUG) {
141             Log.d(TAG, "Writing to device owner file");
142         }
143         return new DeviceOwnerReadWriter().writeToFileLocked();
144     }
145 
146     /**
147      * @return true upon success, false otherwise.
148      */
writeProfileOwner(int userId)149     boolean writeProfileOwner(int userId) {
150         if (DEBUG) {
151             Log.d(TAG, "Writing to profile owner file for user " + userId);
152         }
153         return new ProfileOwnerReadWriter(userId).writeToFileLocked();
154     }
155 
dump(IndentingPrintWriter pw)156     void dump(IndentingPrintWriter pw) {
157         boolean needBlank = false;
158         if (mDeviceOwner != null) {
159             pw.println("Device Owner: ");
160             pw.increaseIndent();
161             mDeviceOwner.dump(pw);
162             pw.println("User ID: " + mDeviceOwnerUserId);
163             pw.decreaseIndent();
164             needBlank = true;
165         }
166         if (mSystemUpdatePolicy != null) {
167             if (needBlank) {
168                 pw.println();
169             }
170             pw.println("System Update Policy: " + mSystemUpdatePolicy);
171             needBlank = true;
172         }
173         if (mProfileOwners != null) {
174             for (Map.Entry<Integer, OwnerInfo> entry : mProfileOwners.entrySet()) {
175                 if (needBlank) {
176                     pw.println();
177                 }
178                 pw.println("Profile Owner (User " + entry.getKey() + "): ");
179                 pw.increaseIndent();
180                 entry.getValue().dump(pw);
181                 pw.decreaseIndent();
182                 needBlank = true;
183             }
184         }
185         if (mSystemUpdateInfo != null) {
186             if (needBlank) {
187                 pw.println();
188             }
189             pw.println("Pending System Update: " + mSystemUpdateInfo);
190             needBlank = true;
191         }
192         if (mSystemUpdateFreezeStart != null || mSystemUpdateFreezeEnd != null) {
193             if (needBlank) {
194                 pw.println();
195             }
196             pw.println("System update freeze record: "
197                     + getSystemUpdateFreezePeriodRecordAsString());
198             needBlank = true;
199         }
200     }
201 
getSystemUpdateFreezePeriodRecordAsString()202     String getSystemUpdateFreezePeriodRecordAsString() {
203         StringBuilder freezePeriodRecord = new StringBuilder();
204         freezePeriodRecord.append("start: ");
205         if (mSystemUpdateFreezeStart != null) {
206             freezePeriodRecord.append(mSystemUpdateFreezeStart.toString());
207         } else {
208             freezePeriodRecord.append("null");
209         }
210         freezePeriodRecord.append("; end: ");
211         if (mSystemUpdateFreezeEnd != null) {
212             freezePeriodRecord.append(mSystemUpdateFreezeEnd.toString());
213         } else {
214             freezePeriodRecord.append("null");
215         }
216         return freezePeriodRecord.toString();
217     }
218 
219     @VisibleForTesting
getDeviceOwnerFile()220     File getDeviceOwnerFile() {
221         return new File(mPathProvider.getDataSystemDirectory(), DEVICE_OWNER_XML);
222     }
223 
224     @VisibleForTesting
getProfileOwnerFile(int userId)225     File getProfileOwnerFile(int userId) {
226         return new File(mPathProvider.getUserSystemDirectory(userId), PROFILE_OWNER_XML);
227     }
228 
229     private abstract static class FileReadWriter {
230         private final File mFile;
231 
FileReadWriter(File file)232         protected FileReadWriter(File file) {
233             mFile = file;
234         }
235 
shouldWrite()236         abstract boolean shouldWrite();
237 
writeToFileLocked()238         boolean writeToFileLocked() {
239             if (!shouldWrite()) {
240                 if (DEBUG) {
241                     Log.d(TAG, "No need to write to " + mFile);
242                 }
243                 // No contents, remove the file.
244                 if (mFile.exists()) {
245                     if (DEBUG) {
246                         Log.d(TAG, "Deleting existing " + mFile);
247                     }
248                     if (!mFile.delete()) {
249                         Slog.e(TAG, "Failed to remove " + mFile.getPath());
250                     }
251                 }
252                 return true;
253             }
254             if (DEBUG) {
255                 Log.d(TAG, "Writing to " + mFile);
256             }
257 
258             final AtomicFile f = new AtomicFile(mFile);
259             FileOutputStream outputStream = null;
260             try {
261                 outputStream = f.startWrite();
262                 final TypedXmlSerializer out = Xml.resolveSerializer(outputStream);
263 
264                 // Root tag
265                 out.startDocument(null, true);
266                 out.startTag(null, TAG_ROOT);
267 
268                 // Actual content
269                 writeInner(out);
270 
271                 // Close root
272                 out.endTag(null, TAG_ROOT);
273                 out.endDocument();
274                 out.flush();
275 
276                 // Commit the content.
277                 f.finishWrite(outputStream);
278                 outputStream = null;
279 
280             } catch (IOException e) {
281                 Slog.e(TAG, "Exception when writing", e);
282                 if (outputStream != null) {
283                     f.failWrite(outputStream);
284                 }
285                 return false;
286             }
287             return true;
288         }
289 
readFromFileLocked()290         void readFromFileLocked() {
291             if (!mFile.exists()) {
292                 if (DEBUG) {
293                     Log.d(TAG, "" + mFile + " doesn't exist");
294                 }
295                 return;
296             }
297             if (DEBUG) {
298                 Log.d(TAG, "Reading from " + mFile);
299             }
300             final AtomicFile f = new AtomicFile(mFile);
301             InputStream input = null;
302             try {
303                 input = f.openRead();
304                 final TypedXmlPullParser parser = Xml.resolvePullParser(input);
305 
306                 int type;
307                 int depth = 0;
308                 while ((type = parser.next()) != TypedXmlPullParser.END_DOCUMENT) {
309                     switch (type) {
310                         case TypedXmlPullParser.START_TAG:
311                             depth++;
312                             break;
313                         case TypedXmlPullParser.END_TAG:
314                             depth--;
315                             // fallthrough
316                         default:
317                             continue;
318                     }
319                     // Check the root tag
320                     final String tag = parser.getName();
321                     if (depth == 1) {
322                         if (!TAG_ROOT.equals(tag)) {
323                             Slog.e(TAG, "Invalid root tag: " + tag);
324                             return;
325                         }
326                         continue;
327                     }
328                     // readInner() will only see START_TAG at depth >= 2.
329                     if (!readInner(parser, depth, tag)) {
330                         return; // Error
331                     }
332                 }
333             } catch (XmlPullParserException | IOException e) {
334                 Slog.e(TAG, "Error parsing owners information file", e);
335             } finally {
336                 IoUtils.closeQuietly(input);
337             }
338         }
339 
writeInner(TypedXmlSerializer out)340         abstract void writeInner(TypedXmlSerializer out) throws IOException;
341 
readInner(TypedXmlPullParser parser, int depth, String tag)342         abstract boolean readInner(TypedXmlPullParser parser, int depth, String tag);
343     }
344 
345     private class DeviceOwnerReadWriter extends FileReadWriter {
346 
DeviceOwnerReadWriter()347         protected DeviceOwnerReadWriter() {
348             super(getDeviceOwnerFile());
349         }
350 
351         @Override
shouldWrite()352         boolean shouldWrite() {
353             return (mDeviceOwner != null) || (mSystemUpdatePolicy != null)
354                     || (mSystemUpdateInfo != null);
355         }
356 
357         @Override
writeInner(TypedXmlSerializer out)358         void writeInner(TypedXmlSerializer out) throws IOException {
359             if (mDeviceOwner != null) {
360                 mDeviceOwner.writeToXml(out, TAG_DEVICE_OWNER);
361                 out.startTag(null, TAG_DEVICE_OWNER_CONTEXT);
362                 out.attributeInt(null, ATTR_USERID, mDeviceOwnerUserId);
363                 out.endTag(null, TAG_DEVICE_OWNER_CONTEXT);
364 
365             }
366 
367             if (!mDeviceOwnerTypes.isEmpty()) {
368                 for (ArrayMap.Entry<String, Integer> entry : mDeviceOwnerTypes.entrySet()) {
369                     out.startTag(null, TAG_DEVICE_OWNER_TYPE);
370                     out.attribute(null, ATTR_PACKAGE, entry.getKey());
371                     out.attributeInt(null, ATTR_DEVICE_OWNER_TYPE_VALUE, entry.getValue());
372                     out.endTag(null, TAG_DEVICE_OWNER_TYPE);
373                 }
374             }
375 
376             if (mSystemUpdatePolicy != null) {
377                 out.startTag(null, TAG_SYSTEM_UPDATE_POLICY);
378                 mSystemUpdatePolicy.saveToXml(out);
379                 out.endTag(null, TAG_SYSTEM_UPDATE_POLICY);
380             }
381 
382             if (mSystemUpdateInfo != null) {
383                 mSystemUpdateInfo.writeToXml(out, TAG_PENDING_OTA_INFO);
384             }
385 
386             if (mSystemUpdateFreezeStart != null || mSystemUpdateFreezeEnd != null) {
387                 out.startTag(null, TAG_FREEZE_PERIOD_RECORD);
388                 if (mSystemUpdateFreezeStart != null) {
389                     out.attribute(
390                             null, ATTR_FREEZE_RECORD_START, mSystemUpdateFreezeStart.toString());
391                 }
392                 if (mSystemUpdateFreezeEnd != null) {
393                     out.attribute(null, ATTR_FREEZE_RECORD_END, mSystemUpdateFreezeEnd.toString());
394                 }
395                 out.endTag(null, TAG_FREEZE_PERIOD_RECORD);
396             }
397 
398             out.startTag(null, TAG_POLICY_ENGINE_MIGRATION);
399             out.attributeBoolean(null, ATTR_MIGRATED_TO_POLICY_ENGINE, mMigratedToPolicyEngine);
400             out.endTag(null, TAG_POLICY_ENGINE_MIGRATION);
401 
402         }
403 
404         @Override
readInner(TypedXmlPullParser parser, int depth, String tag)405         boolean readInner(TypedXmlPullParser parser, int depth, String tag) {
406             if (depth > 2) {
407                 return true; // Ignore
408             }
409             switch (tag) {
410                 case TAG_DEVICE_OWNER:
411                     mDeviceOwner = OwnerInfo.readFromXml(parser);
412                     mDeviceOwnerUserId = UserHandle.USER_SYSTEM; // Set default
413                     break;
414                 case TAG_DEVICE_OWNER_CONTEXT: {
415                     mDeviceOwnerUserId =
416                             parser.getAttributeInt(null, ATTR_USERID, mDeviceOwnerUserId);
417                     break;
418                 }
419                 case TAG_SYSTEM_UPDATE_POLICY:
420                     mSystemUpdatePolicy = SystemUpdatePolicy.restoreFromXml(parser);
421                     break;
422                 case TAG_PENDING_OTA_INFO:
423                     mSystemUpdateInfo = SystemUpdateInfo.readFromXml(parser);
424                     break;
425                 case TAG_FREEZE_PERIOD_RECORD:
426                     String startDate = parser.getAttributeValue(null, ATTR_FREEZE_RECORD_START);
427                     String endDate = parser.getAttributeValue(null, ATTR_FREEZE_RECORD_END);
428                     if (startDate != null && endDate != null) {
429                         mSystemUpdateFreezeStart = LocalDate.parse(startDate);
430                         mSystemUpdateFreezeEnd = LocalDate.parse(endDate);
431                         if (mSystemUpdateFreezeStart.isAfter(mSystemUpdateFreezeEnd)) {
432                             Slog.e(TAG, "Invalid system update freeze record loaded");
433                             mSystemUpdateFreezeStart = null;
434                             mSystemUpdateFreezeEnd = null;
435                         }
436                     }
437                     break;
438                 case TAG_DEVICE_OWNER_TYPE:
439                     String packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
440                     int deviceOwnerType = parser.getAttributeInt(
441                             null, ATTR_DEVICE_OWNER_TYPE_VALUE, DEVICE_OWNER_TYPE_DEFAULT);
442                     mDeviceOwnerTypes.put(packageName, deviceOwnerType);
443                     break;
444                 // Deprecated fields below.
445                 case TAG_DEVICE_OWNER_PROTECTED_PACKAGES:
446                     packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
447                     int protectedPackagesSize = parser.getAttributeInt(null, ATTR_SIZE, 0);
448                     List<String> protectedPackages = new ArrayList<>();
449                     for (int i = 0; i < protectedPackagesSize; i++) {
450                         protectedPackages.add(parser.getAttributeValue(null, ATTR_NAME + i));
451                     }
452                     if (mDeviceOwnerProtectedPackages == null) {
453                         mDeviceOwnerProtectedPackages = new ArrayMap<>();
454                     }
455                     mDeviceOwnerProtectedPackages.put(packageName, protectedPackages);
456                     break;
457                 case TAG_POLICY_ENGINE_MIGRATION:
458                     mMigratedToPolicyEngine = parser.getAttributeBoolean(
459                             null, ATTR_MIGRATED_TO_POLICY_ENGINE, false);
460                     break;
461                 default:
462                     Slog.e(TAG, "Unexpected tag: " + tag);
463                     return false;
464 
465             }
466             return true;
467         }
468     }
469 
470     private class ProfileOwnerReadWriter extends FileReadWriter {
471         private final int mUserId;
472 
ProfileOwnerReadWriter(int userId)473         ProfileOwnerReadWriter(int userId) {
474             super(getProfileOwnerFile(userId));
475             mUserId = userId;
476         }
477 
478         @Override
shouldWrite()479         boolean shouldWrite() {
480             return mProfileOwners.get(mUserId) != null;
481         }
482 
483         @Override
writeInner(TypedXmlSerializer out)484         void writeInner(TypedXmlSerializer out) throws IOException {
485             final OwnerInfo profileOwner = mProfileOwners.get(mUserId);
486             if (profileOwner != null) {
487                 profileOwner.writeToXml(out, TAG_PROFILE_OWNER);
488             }
489         }
490 
491         @Override
readInner(TypedXmlPullParser parser, int depth, String tag)492         boolean readInner(TypedXmlPullParser parser, int depth, String tag) {
493             if (depth > 2) {
494                 return true; // Ignore
495             }
496             switch (tag) {
497                 case TAG_PROFILE_OWNER:
498                     mProfileOwners.put(mUserId, OwnerInfo.readFromXml(parser));
499                     break;
500                 default:
501                     Slog.e(TAG, "Unexpected tag: " + tag);
502                     return false;
503 
504             }
505             return true;
506         }
507     }
508 
509     static class OwnerInfo {
510         public final String packageName;
511         public final ComponentName admin;
512         public String remoteBugreportUri;
513         public String remoteBugreportHash;
514         public boolean isOrganizationOwnedDevice;
515 
OwnerInfo(ComponentName admin, String remoteBugreportUri, String remoteBugreportHash, boolean isOrganizationOwnedDevice)516         OwnerInfo(ComponentName admin, String remoteBugreportUri,
517                 String remoteBugreportHash, boolean isOrganizationOwnedDevice) {
518             this.admin = admin;
519             this.packageName = admin.getPackageName();
520             this.remoteBugreportUri = remoteBugreportUri;
521             this.remoteBugreportHash = remoteBugreportHash;
522             this.isOrganizationOwnedDevice = isOrganizationOwnedDevice;
523         }
524 
writeToXml(TypedXmlSerializer out, String tag)525         public void writeToXml(TypedXmlSerializer out, String tag) throws IOException {
526             out.startTag(null, tag);
527             if (admin != null) {
528                 out.attribute(null, ATTR_COMPONENT_NAME, admin.flattenToString());
529             }
530             if (remoteBugreportUri != null) {
531                 out.attribute(null, ATTR_REMOTE_BUGREPORT_URI, remoteBugreportUri);
532             }
533             if (remoteBugreportHash != null) {
534                 out.attribute(null, ATTR_REMOTE_BUGREPORT_HASH, remoteBugreportHash);
535             }
536             if (isOrganizationOwnedDevice) {
537                 out.attributeBoolean(
538                         null, ATTR_PROFILE_OWNER_OF_ORG_OWNED_DEVICE, isOrganizationOwnedDevice);
539             }
540             out.endTag(null, tag);
541         }
542 
readFromXml(TypedXmlPullParser parser)543         public static OwnerInfo readFromXml(TypedXmlPullParser parser) {
544             final String componentName = parser.getAttributeValue(null, ATTR_COMPONENT_NAME);
545             final String remoteBugreportUri =
546                     parser.getAttributeValue(null, ATTR_REMOTE_BUGREPORT_URI);
547             final String remoteBugreportHash =
548                     parser.getAttributeValue(null, ATTR_REMOTE_BUGREPORT_HASH);
549             final String canAccessDeviceIdsStr =
550                     parser.getAttributeValue(null, ATTR_CAN_ACCESS_DEVICE_IDS);
551             final boolean canAccessDeviceIds = "true".equals(canAccessDeviceIdsStr);
552             final String isOrgOwnedDeviceStr =
553                     parser.getAttributeValue(null, ATTR_PROFILE_OWNER_OF_ORG_OWNED_DEVICE);
554             final boolean isOrgOwnedDevice =
555                     "true".equals(isOrgOwnedDeviceStr) | canAccessDeviceIds;
556 
557             if (componentName == null) {
558                 Slog.e(TAG, "Owner component not found");
559                 return null;
560             }
561             final ComponentName admin = ComponentName.unflattenFromString(componentName);
562             if (admin == null) {
563                 Slog.e(TAG, "Owner component not parsable: " + componentName);
564                 return null;
565             }
566 
567             return new OwnerInfo(admin, remoteBugreportUri, remoteBugreportHash, isOrgOwnedDevice);
568         }
569 
dump(IndentingPrintWriter pw)570         public void dump(IndentingPrintWriter pw) {
571             pw.println("admin=" + admin);
572             pw.println("package=" + packageName);
573             pw.println("isOrganizationOwnedDevice=" + isOrganizationOwnedDevice);
574         }
575     }
576 }
577