• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright (C) 2010 The Android Open Source Project.
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *      http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 package com.android.exchange.adapter;
17 
18 import android.app.admin.DevicePolicyManager;
19 import android.content.Context;
20 import android.content.res.Resources;
21 import android.os.storage.StorageManager;
22 import android.os.storage.StorageVolume;
23 
24 import com.android.emailcommon.provider.Policy;
25 import com.android.exchange.EasSyncService;
26 import com.android.exchange.R;
27 
28 import org.xmlpull.v1.XmlPullParser;
29 import org.xmlpull.v1.XmlPullParserException;
30 import org.xmlpull.v1.XmlPullParserFactory;
31 
32 import java.io.ByteArrayInputStream;
33 import java.io.IOException;
34 import java.io.InputStream;
35 import java.util.ArrayList;
36 
37 /**
38  * Parse the result of the Provision command
39  */
40 public class ProvisionParser extends Parser {
41     private final EasSyncService mService;
42     private Policy mPolicy = null;
43     private String mSecuritySyncKey = null;
44     private boolean mRemoteWipe = false;
45     private boolean mIsSupportable = true;
46     private boolean smimeRequired = false;
47     private final Resources mResources;
48 
ProvisionParser(InputStream in, EasSyncService service)49     public ProvisionParser(InputStream in, EasSyncService service) throws IOException {
50         super(in);
51         mService = service;
52         mResources = service.mContext.getResources();
53     }
54 
getPolicy()55     public Policy getPolicy() {
56         return mPolicy;
57     }
58 
getSecuritySyncKey()59     public String getSecuritySyncKey() {
60         return mSecuritySyncKey;
61     }
62 
setSecuritySyncKey(String securitySyncKey)63     public void setSecuritySyncKey(String securitySyncKey) {
64         mSecuritySyncKey = securitySyncKey;
65     }
66 
getRemoteWipe()67     public boolean getRemoteWipe() {
68         return mRemoteWipe;
69     }
70 
hasSupportablePolicySet()71     public boolean hasSupportablePolicySet() {
72         return (mPolicy != null) && mIsSupportable;
73     }
74 
clearUnsupportablePolicies()75     public void clearUnsupportablePolicies() {
76         mIsSupportable = true;
77         mPolicy.mProtocolPoliciesUnsupported = null;
78     }
79 
addPolicyString(StringBuilder sb, int res)80     private void addPolicyString(StringBuilder sb, int res) {
81         sb.append(mResources.getString(res));
82         sb.append(Policy.POLICY_STRING_DELIMITER);
83     }
84 
85     /**
86      * Complete setup of a Policy; we normalize it first (removing inconsistencies, etc.) and then
87      * generate the tokenized "protocol policies enforced" string.  Note that unsupported policies
88      * must have been added prior to calling this method (this is only a possibility with wbxml
89      * policy documents, as all versions of the OS support the policies in xml documents).
90      */
setPolicy(Policy policy)91     private void setPolicy(Policy policy) {
92         policy.normalize();
93         StringBuilder sb = new StringBuilder();
94         if (policy.mDontAllowAttachments) {
95             addPolicyString(sb, R.string.policy_dont_allow_attachments);
96         }
97         if (policy.mRequireManualSyncWhenRoaming) {
98             addPolicyString(sb, R.string.policy_require_manual_sync_roaming);
99         }
100         policy.mProtocolPoliciesEnforced = sb.toString();
101         mPolicy = policy;
102     }
103 
deviceSupportsEncryption()104     private boolean deviceSupportsEncryption() {
105         DevicePolicyManager dpm = (DevicePolicyManager)
106                 mService.mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
107         int status = dpm.getStorageEncryptionStatus();
108         return status != DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
109     }
110 
parseProvisionDocWbxml()111     private void parseProvisionDocWbxml() throws IOException {
112         Policy policy = new Policy();
113         ArrayList<Integer> unsupportedList = new ArrayList<Integer>();
114         boolean passwordEnabled = false;
115 
116         while (nextTag(Tags.PROVISION_EAS_PROVISION_DOC) != END) {
117             boolean tagIsSupported = true;
118             int res = 0;
119             switch (tag) {
120                 case Tags.PROVISION_DEVICE_PASSWORD_ENABLED:
121                     if (getValueInt() == 1) {
122                         passwordEnabled = true;
123                         if (policy.mPasswordMode == Policy.PASSWORD_MODE_NONE) {
124                             policy.mPasswordMode = Policy.PASSWORD_MODE_SIMPLE;
125                         }
126                     }
127                     break;
128                 case Tags.PROVISION_MIN_DEVICE_PASSWORD_LENGTH:
129                     policy.mPasswordMinLength = getValueInt();
130                     break;
131                 case Tags.PROVISION_ALPHA_DEVICE_PASSWORD_ENABLED:
132                     if (getValueInt() == 1) {
133                         policy.mPasswordMode = Policy.PASSWORD_MODE_STRONG;
134                     }
135                     break;
136                 case Tags.PROVISION_MAX_INACTIVITY_TIME_DEVICE_LOCK:
137                     // EAS gives us seconds, which is, happily, what the PolicySet requires
138                     policy.mMaxScreenLockTime = getValueInt();
139                     break;
140                 case Tags.PROVISION_MAX_DEVICE_PASSWORD_FAILED_ATTEMPTS:
141                     policy.mPasswordMaxFails = getValueInt();
142                     break;
143                 case Tags.PROVISION_DEVICE_PASSWORD_EXPIRATION:
144                     policy.mPasswordExpirationDays = getValueInt();
145                     break;
146                 case Tags.PROVISION_DEVICE_PASSWORD_HISTORY:
147                     policy.mPasswordHistory = getValueInt();
148                     break;
149                 case Tags.PROVISION_ALLOW_CAMERA:
150                     policy.mDontAllowCamera = (getValueInt() == 0);
151                     break;
152                 case Tags.PROVISION_ALLOW_SIMPLE_DEVICE_PASSWORD:
153                     // Ignore this unless there's any MSFT documentation for what this means
154                     // Hint: I haven't seen any that's more specific than "simple"
155                     getValue();
156                     break;
157                 // The following policies, if false, can't be supported at the moment
158                 case Tags.PROVISION_ALLOW_STORAGE_CARD:
159                 case Tags.PROVISION_ALLOW_UNSIGNED_APPLICATIONS:
160                 case Tags.PROVISION_ALLOW_UNSIGNED_INSTALLATION_PACKAGES:
161                 case Tags.PROVISION_ALLOW_WIFI:
162                 case Tags.PROVISION_ALLOW_TEXT_MESSAGING:
163                 case Tags.PROVISION_ALLOW_POP_IMAP_EMAIL:
164                 case Tags.PROVISION_ALLOW_IRDA:
165                 case Tags.PROVISION_ALLOW_HTML_EMAIL:
166                 case Tags.PROVISION_ALLOW_BROWSER:
167                 case Tags.PROVISION_ALLOW_CONSUMER_EMAIL:
168                 case Tags.PROVISION_ALLOW_INTERNET_SHARING:
169                     if (getValueInt() == 0) {
170                         tagIsSupported = false;
171                         switch(tag) {
172                             case Tags.PROVISION_ALLOW_STORAGE_CARD:
173                                 res = R.string.policy_dont_allow_storage_cards;
174                                 break;
175                             case Tags.PROVISION_ALLOW_UNSIGNED_APPLICATIONS:
176                                 res = R.string.policy_dont_allow_unsigned_apps;
177                                 break;
178                             case Tags.PROVISION_ALLOW_UNSIGNED_INSTALLATION_PACKAGES:
179                                 res = R.string.policy_dont_allow_unsigned_installers;
180                                 break;
181                             case Tags.PROVISION_ALLOW_WIFI:
182                                 res = R.string.policy_dont_allow_wifi;
183                                 break;
184                             case Tags.PROVISION_ALLOW_TEXT_MESSAGING:
185                                 res = R.string.policy_dont_allow_text_messaging;
186                                 break;
187                             case Tags.PROVISION_ALLOW_POP_IMAP_EMAIL:
188                                 res = R.string.policy_dont_allow_pop_imap;
189                                 break;
190                             case Tags.PROVISION_ALLOW_IRDA:
191                                 res = R.string.policy_dont_allow_irda;
192                                 break;
193                             case Tags.PROVISION_ALLOW_HTML_EMAIL:
194                                 res = R.string.policy_dont_allow_html;
195                                 policy.mDontAllowHtml = true;
196                                 break;
197                             case Tags.PROVISION_ALLOW_BROWSER:
198                                 res = R.string.policy_dont_allow_browser;
199                                 break;
200                             case Tags.PROVISION_ALLOW_CONSUMER_EMAIL:
201                                 res = R.string.policy_dont_allow_consumer_email;
202                                 break;
203                             case Tags.PROVISION_ALLOW_INTERNET_SHARING:
204                                 res = R.string.policy_dont_allow_internet_sharing;
205                                 break;
206                         }
207                         if (res > 0) {
208                             unsupportedList.add(res);
209                         }
210                     }
211                     break;
212                 case Tags.PROVISION_ATTACHMENTS_ENABLED:
213                     policy.mDontAllowAttachments = getValueInt() != 1;
214                     break;
215                 // Bluetooth: 0 = no bluetooth; 1 = only hands-free; 2 = allowed
216                 case Tags.PROVISION_ALLOW_BLUETOOTH:
217                     if (getValueInt() != 2) {
218                         tagIsSupported = false;
219                         unsupportedList.add(R.string.policy_bluetooth_restricted);
220                     }
221                     break;
222                 // We may now support device (internal) encryption; we'll check this capability
223                 // below with the call to SecurityPolicy.isSupported()
224                 case Tags.PROVISION_REQUIRE_DEVICE_ENCRYPTION:
225                     if (getValueInt() == 1) {
226                          if (!deviceSupportsEncryption()) {
227                             tagIsSupported = false;
228                             unsupportedList.add(R.string.policy_require_encryption);
229                         } else {
230                             policy.mRequireEncryption = true;
231                         }
232                     }
233                     break;
234                 // Note that DEVICE_ENCRYPTION_ENABLED refers to SD card encryption, which the OS
235                 // does not yet support.
236                 case Tags.PROVISION_DEVICE_ENCRYPTION_ENABLED:
237                     if (getValueInt() == 1) {
238                         log("Policy requires SD card encryption");
239                         // Let's see if this can be supported on our device...
240                         if (deviceSupportsEncryption()) {
241                             StorageManager sm = (StorageManager)mService.mContext.getSystemService(
242                                     Context.STORAGE_SERVICE);
243                             // NOTE: Private API!
244                             // Go through volumes; if ANY are removable, we can't support this
245                             // policy.
246                             StorageVolume[] volumeList = sm.getVolumeList();
247                             for (StorageVolume volume: volumeList) {
248                                 if (volume.isRemovable()) {
249                                     tagIsSupported = false;
250                                     log("Removable: " + volume.getDescription(mService.mContext));
251                                     break;  // Break only from the storage volume loop
252                                 } else {
253                                     log("Not Removable: " + volume.getDescription(mService.mContext));
254                                 }
255                             }
256                             if (tagIsSupported) {
257                                 // If this policy is requested, we MUST also require encryption
258                                 log("Device supports SD card encryption");
259                                 policy.mRequireEncryption = true;
260                                 break;
261                             }
262                         } else {
263                             log("Device doesn't support encryption; failing");
264                             tagIsSupported = false;
265                         }
266                         // If we fall through, we can't support the policy
267                         unsupportedList.add(R.string.policy_require_sd_encryption);
268                     }
269                     break;
270                     // Note this policy; we enforce it in ExchangeService
271                 case Tags.PROVISION_REQUIRE_MANUAL_SYNC_WHEN_ROAMING:
272                     policy.mRequireManualSyncWhenRoaming = getValueInt() == 1;
273                     break;
274                 // We are allowed to accept policies, regardless of value of this tag
275                 // TODO: When we DO support a recovery password, we need to store the value in
276                 // the account (so we know to utilize it)
277                 case Tags.PROVISION_PASSWORD_RECOVERY_ENABLED:
278                     // Read, but ignore, value
279                     policy.mPasswordRecoveryEnabled = getValueInt() == 1;
280                     break;
281                 // The following policies, if true, can't be supported at the moment
282                 case Tags.PROVISION_REQUIRE_SIGNED_SMIME_MESSAGES:
283                 case Tags.PROVISION_REQUIRE_ENCRYPTED_SMIME_MESSAGES:
284                 case Tags.PROVISION_REQUIRE_SIGNED_SMIME_ALGORITHM:
285                 case Tags.PROVISION_REQUIRE_ENCRYPTION_SMIME_ALGORITHM:
286                     if (getValueInt() == 1) {
287                         tagIsSupported = false;
288                         if (!smimeRequired) {
289                             unsupportedList.add(R.string.policy_require_smime);
290                             smimeRequired = true;
291                         }
292                     }
293                     break;
294                 case Tags.PROVISION_MAX_ATTACHMENT_SIZE:
295                     int max = getValueInt();
296                     if (max > 0) {
297                         policy.mMaxAttachmentSize = max;
298                     }
299                     break;
300                 // Complex characters are supported
301                 case Tags.PROVISION_MIN_DEVICE_PASSWORD_COMPLEX_CHARS:
302                     policy.mPasswordComplexChars = getValueInt();
303                     break;
304                 // The following policies are moot; they allow functionality that we don't support
305                 case Tags.PROVISION_ALLOW_DESKTOP_SYNC:
306                 case Tags.PROVISION_ALLOW_SMIME_ENCRYPTION_NEGOTIATION:
307                 case Tags.PROVISION_ALLOW_SMIME_SOFT_CERTS:
308                 case Tags.PROVISION_ALLOW_REMOTE_DESKTOP:
309                     skipTag();
310                     break;
311                 // We don't handle approved/unapproved application lists
312                 case Tags.PROVISION_UNAPPROVED_IN_ROM_APPLICATION_LIST:
313                 case Tags.PROVISION_APPROVED_APPLICATION_LIST:
314                     // Parse and throw away the content
315                     if (specifiesApplications(tag)) {
316                         tagIsSupported = false;
317                         if (tag == Tags.PROVISION_UNAPPROVED_IN_ROM_APPLICATION_LIST) {
318                             unsupportedList.add(R.string.policy_app_blacklist);
319                         } else {
320                             unsupportedList.add(R.string.policy_app_whitelist);
321                         }
322                     }
323                     break;
324                 // We accept calendar age, since we never ask for more than two weeks, and that's
325                 // the most restrictive policy
326                 case Tags.PROVISION_MAX_CALENDAR_AGE_FILTER:
327                     policy.mMaxCalendarLookback = getValueInt();
328                     break;
329                 // We handle max email lookback
330                 case Tags.PROVISION_MAX_EMAIL_AGE_FILTER:
331                     policy.mMaxEmailLookback = getValueInt();
332                     break;
333                 // We currently reject these next two policies
334                 case Tags.PROVISION_MAX_EMAIL_BODY_TRUNCATION_SIZE:
335                 case Tags.PROVISION_MAX_EMAIL_HTML_BODY_TRUNCATION_SIZE:
336                     String value = getValue();
337                     // -1 indicates no required truncation
338                     if (!value.equals("-1")) {
339                         max = Integer.parseInt(value);
340                         if (tag == Tags.PROVISION_MAX_EMAIL_BODY_TRUNCATION_SIZE) {
341                             policy.mMaxTextTruncationSize = max;
342                             unsupportedList.add(R.string.policy_text_truncation);
343                         } else {
344                             policy.mMaxHtmlTruncationSize = max;
345                             unsupportedList.add(R.string.policy_html_truncation);
346                         }
347                         tagIsSupported = false;
348                     }
349                     break;
350                 default:
351                     skipTag();
352             }
353 
354             if (!tagIsSupported) {
355                 log("Policy not supported: " + tag);
356                 mIsSupportable = false;
357             }
358         }
359 
360         // Make sure policy settings are valid; password not enabled trumps other password settings
361         if (!passwordEnabled) {
362             policy.mPasswordMode = Policy.PASSWORD_MODE_NONE;
363         }
364 
365         if (!unsupportedList.isEmpty()) {
366             StringBuilder sb = new StringBuilder();
367             for (int res: unsupportedList) {
368                 addPolicyString(sb, res);
369             }
370             policy.mProtocolPoliciesUnsupported = sb.toString();
371         }
372 
373         setPolicy(policy);
374     }
375 
376     /**
377      * Return whether or not either of the application list tags specifies any applications
378      * @param endTag the tag whose children we're walking through
379      * @return whether any applications were specified (by name or by hash)
380      * @throws IOException
381      */
specifiesApplications(int endTag)382     private boolean specifiesApplications(int endTag) throws IOException {
383         boolean specifiesApplications = false;
384         while (nextTag(endTag) != END) {
385             switch (tag) {
386                 case Tags.PROVISION_APPLICATION_NAME:
387                 case Tags.PROVISION_HASH:
388                     specifiesApplications = true;
389                     break;
390                 default:
391                     skipTag();
392             }
393         }
394         return specifiesApplications;
395     }
396 
parseProvisionDocXml(String doc)397     /*package*/ void parseProvisionDocXml(String doc) throws IOException {
398         Policy policy = new Policy();
399 
400         try {
401             XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
402             XmlPullParser parser = factory.newPullParser();
403             parser.setInput(new ByteArrayInputStream(doc.getBytes()), "UTF-8");
404             int type = parser.getEventType();
405             if (type == XmlPullParser.START_DOCUMENT) {
406                 type = parser.next();
407                 if (type == XmlPullParser.START_TAG) {
408                     String tagName = parser.getName();
409                     if (tagName.equals("wap-provisioningdoc")) {
410                         parseWapProvisioningDoc(parser, policy);
411                     }
412                 }
413             }
414         } catch (XmlPullParserException e) {
415            throw new IOException();
416         }
417 
418         setPolicy(policy);
419     }
420 
421     /**
422      * Return true if password is required; otherwise false.
423      */
parseSecurityPolicy(XmlPullParser parser, Policy policy)424     private boolean parseSecurityPolicy(XmlPullParser parser, Policy policy)
425             throws XmlPullParserException, IOException {
426         boolean passwordRequired = true;
427         while (true) {
428             int type = parser.nextTag();
429             if (type == XmlPullParser.END_TAG && parser.getName().equals("characteristic")) {
430                 break;
431             } else if (type == XmlPullParser.START_TAG) {
432                 String tagName = parser.getName();
433                 if (tagName.equals("parm")) {
434                     String name = parser.getAttributeValue(null, "name");
435                     if (name.equals("4131")) {
436                         String value = parser.getAttributeValue(null, "value");
437                         if (value.equals("1")) {
438                             passwordRequired = false;
439                         }
440                     }
441                 }
442             }
443         }
444         return passwordRequired;
445     }
446 
parseCharacteristic(XmlPullParser parser, Policy policy)447     private void parseCharacteristic(XmlPullParser parser, Policy policy)
448             throws XmlPullParserException, IOException {
449         boolean enforceInactivityTimer = true;
450         while (true) {
451             int type = parser.nextTag();
452             if (type == XmlPullParser.END_TAG && parser.getName().equals("characteristic")) {
453                 break;
454             } else if (type == XmlPullParser.START_TAG) {
455                 if (parser.getName().equals("parm")) {
456                     String name = parser.getAttributeValue(null, "name");
457                     String value = parser.getAttributeValue(null, "value");
458                     if (name.equals("AEFrequencyValue")) {
459                         if (enforceInactivityTimer) {
460                             if (value.equals("0")) {
461                                 policy.mMaxScreenLockTime = 1;
462                             } else {
463                                 policy.mMaxScreenLockTime = 60*Integer.parseInt(value);
464                             }
465                         }
466                     } else if (name.equals("AEFrequencyType")) {
467                         // "0" here means we don't enforce an inactivity timeout
468                         if (value.equals("0")) {
469                             enforceInactivityTimer = false;
470                         }
471                     } else if (name.equals("DeviceWipeThreshold")) {
472                         policy.mPasswordMaxFails = Integer.parseInt(value);
473                     } else if (name.equals("CodewordFrequency")) {
474                         // Ignore; has no meaning for us
475                     } else if (name.equals("MinimumPasswordLength")) {
476                         policy.mPasswordMinLength = Integer.parseInt(value);
477                     } else if (name.equals("PasswordComplexity")) {
478                         if (value.equals("0")) {
479                             policy.mPasswordMode = Policy.PASSWORD_MODE_STRONG;
480                         } else {
481                             policy.mPasswordMode = Policy.PASSWORD_MODE_SIMPLE;
482                         }
483                     }
484                 }
485             }
486         }
487     }
488 
parseRegistry(XmlPullParser parser, Policy policy)489     private void parseRegistry(XmlPullParser parser, Policy policy)
490             throws XmlPullParserException, IOException {
491       while (true) {
492           int type = parser.nextTag();
493           if (type == XmlPullParser.END_TAG && parser.getName().equals("characteristic")) {
494               break;
495           } else if (type == XmlPullParser.START_TAG) {
496               String name = parser.getName();
497               if (name.equals("characteristic")) {
498                   parseCharacteristic(parser, policy);
499               }
500           }
501       }
502     }
503 
parseWapProvisioningDoc(XmlPullParser parser, Policy policy)504     private void parseWapProvisioningDoc(XmlPullParser parser, Policy policy)
505             throws XmlPullParserException, IOException {
506         while (true) {
507             int type = parser.nextTag();
508             if (type == XmlPullParser.END_TAG && parser.getName().equals("wap-provisioningdoc")) {
509                 break;
510             } else if (type == XmlPullParser.START_TAG) {
511                 String name = parser.getName();
512                 if (name.equals("characteristic")) {
513                     String atype = parser.getAttributeValue(null, "type");
514                     if (atype.equals("SecurityPolicy")) {
515                         // If a password isn't required, stop here
516                         if (!parseSecurityPolicy(parser, policy)) {
517                             return;
518                         }
519                     } else if (atype.equals("Registry")) {
520                         parseRegistry(parser, policy);
521                         return;
522                     }
523                 }
524             }
525         }
526     }
527 
parseProvisionData()528     private void parseProvisionData() throws IOException {
529         while (nextTag(Tags.PROVISION_DATA) != END) {
530             if (tag == Tags.PROVISION_EAS_PROVISION_DOC) {
531                 parseProvisionDocWbxml();
532             } else {
533                 skipTag();
534             }
535         }
536     }
537 
parsePolicy()538     private void parsePolicy() throws IOException {
539         String policyType = null;
540         while (nextTag(Tags.PROVISION_POLICY) != END) {
541             switch (tag) {
542                 case Tags.PROVISION_POLICY_TYPE:
543                     policyType = getValue();
544                     mService.userLog("Policy type: ", policyType);
545                     break;
546                 case Tags.PROVISION_POLICY_KEY:
547                     mSecuritySyncKey = getValue();
548                     break;
549                 case Tags.PROVISION_STATUS:
550                     mService.userLog("Policy status: ", getValue());
551                     break;
552                 case Tags.PROVISION_DATA:
553                     if (policyType.equalsIgnoreCase(EasSyncService.EAS_2_POLICY_TYPE)) {
554                         // Parse the old style XML document
555                         parseProvisionDocXml(getValue());
556                     } else {
557                         // Parse the newer WBXML data
558                         parseProvisionData();
559                     }
560                     break;
561                 default:
562                     skipTag();
563             }
564         }
565     }
566 
parsePolicies()567     private void parsePolicies() throws IOException {
568         while (nextTag(Tags.PROVISION_POLICIES) != END) {
569             if (tag == Tags.PROVISION_POLICY) {
570                 parsePolicy();
571             } else {
572                 skipTag();
573             }
574         }
575     }
576 
parseDeviceInformation()577     private void parseDeviceInformation() throws IOException {
578         while (nextTag(Tags.SETTINGS_DEVICE_INFORMATION) != END) {
579             if (tag == Tags.SETTINGS_STATUS) {
580                 mService.userLog("DeviceInformation status: " + getValue());
581             } else {
582                 skipTag();
583             }
584         }
585     }
586 
587     @Override
parse()588     public boolean parse() throws IOException {
589         boolean res = false;
590         if (nextTag(START_DOCUMENT) != Tags.PROVISION_PROVISION) {
591             throw new IOException();
592         }
593         while (nextTag(START_DOCUMENT) != END_DOCUMENT) {
594             switch (tag) {
595                 case Tags.PROVISION_STATUS:
596                     int status = getValueInt();
597                     mService.userLog("Provision status: ", status);
598                     res = (status == 1);
599                     break;
600                 case Tags.SETTINGS_DEVICE_INFORMATION:
601                     parseDeviceInformation();
602                     break;
603                 case Tags.PROVISION_POLICIES:
604                     parsePolicies();
605                     break;
606                 case Tags.PROVISION_REMOTE_WIPE:
607                     // Indicate remote wipe command received
608                     mRemoteWipe = true;
609                     break;
610                 default:
611                     skipTag();
612             }
613         }
614         return res;
615     }
616 }
617