Overview

Packages

  • ActiveSync
  • None

Classes

  • Horde_ActiveSync
  • Horde_ActiveSync_Connector_Exporter
  • Horde_ActiveSync_Connector_Importer
  • Horde_ActiveSync_Driver_Base
  • Horde_ActiveSync_Exception
  • Horde_ActiveSync_Exception_InvalidRequest
  • Horde_ActiveSync_Exception_StateGone
  • Horde_ActiveSync_Message_Base
  • Horde_ActiveSync_Request_Base
  • Horde_ActiveSync_Request_FolderCreate
  • Horde_ActiveSync_Request_FolderSync
  • Horde_ActiveSync_Request_GetHierarchy
  • Horde_ActiveSync_Request_GetItemEstimate
  • Horde_ActiveSync_Request_MeetingResponse
  • Horde_ActiveSync_Request_MoveItems
  • Horde_ActiveSync_Request_Notify
  • Horde_ActiveSync_Request_Ping
  • Horde_ActiveSync_Request_Provision
  • Horde_ActiveSync_Request_Search
  • Horde_ActiveSync_Request_SendMail
  • Horde_ActiveSync_Request_SmartForward
  • Horde_ActiveSync_Request_SmartReply
  • Horde_ActiveSync_Request_Sync
  • Horde_ActiveSync_State_File
  • Horde_ActiveSync_Sync
  • Horde_ActiveSync_Wbxml
  • Horde_ActiveSync_Wbxml_Decoder
  • Horde_ActiveSync_Wbxml_Encoder
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: /**
  3:  * Handle PROVISION requests
  4:  *
  5:  * Logic adapted from Z-Push, original copyright notices below.
  6:  *
  7:  * Copyright 2009-2012 Horde LLC (http://www.horde.org/)
  8:  *
  9:  * @author Michael J. Rubinsky <mrubinsk@horde.org>
 10:  * @package ActiveSync
 11:  */
 12: /**
 13:  * Zarafa Deutschland GmbH, www.zarafaserver.de
 14:  * This file is distributed under GPL-2.0.
 15:  * Consult COPYING file for details
 16:  */
 17: class Horde_ActiveSync_Request_Provision extends Horde_ActiveSync_Request_Base
 18: {
 19: 
 20:     /* Status Constants */
 21:     const STATUS_SUCCESS           = 1;
 22:     const STATUS_PROTERROR         = 2; // Global status
 23:     const STATUS_NOTDEFINED        = 2; // Policy status
 24: 
 25:     const STATUS_SERVERERROR       = 3; // Global
 26:     const STATUS_POLICYUNKNOWN     = 3; // Policy
 27: 
 28:     const STATUS_DEVEXTMANAGED     = 4; // Global
 29:     const STATUS_POLICYCORRUPT     = 4; // Policy
 30: 
 31:     const STATUS_POLKEYMISM        = 5;
 32: 
 33:     /* Client -> Server Status */
 34:     const STATUS_CLIENT_SUCCESS    = 1;
 35:     const STATUS_CLIENT_PARTIAL    = 2; // Only pin was enabled.
 36:     const STATUS_CLIENT_FAILED     = 3; // No policies applied at all.
 37:     const STATUS_CLIENT_THIRDPARTY = 4; // Client provisioned by 3rd party?
 38: 
 39:     const POLICYTYPE_XML           = 'MS-WAP-Provisioning-XML';
 40:     const POLICYTYPE_WBXML         = 'MS-EAS-Provisioning-WBXML';
 41: 
 42:     /**
 43:      * Handle the Provision request. This is a 3-phase process. Phase 1 is
 44:      * actually the enforcement, when the server rejects a request and forces
 45:      * the client to perform this PROVISION request...so we are handling phase
 46:      * 2 (download policies) and 3 (acknowledge policies) here.
 47:      *
 48:      * @return boolean
 49:      * @throws Horde_ActiveSync_Exception
 50:      */
 51:     public function handle()
 52:     {
 53:         parent::handle();
 54: 
 55:         // Be optimistic
 56:         $status = self::STATUS_SUCCESS;
 57:         $policyStatus = self::STATUS_SUCCESS;
 58: 
 59:         // Start by assuming we are in stage 2
 60:         $phase2 = true;
 61:         if (!$this->_decoder->getElementStartTag(Horde_ActiveSync::PROVISION_PROVISION)) {
 62:             return $this->_globalError(self::STATUS_PROTERROR);
 63:         }
 64: 
 65:         // Handle android remote wipe
 66:         if ($this->_decoder->getElementStartTag(Horde_ActiveSync::PROVISION_REMOTEWIPE)) {
 67:             if (!$this->_decoder->getElementStartTag(Horde_ActiveSync::PROVISION_STATUS)) {
 68:                 return $this->_globalError(self::STATUS_PROTERROR);
 69:             }
 70:             $status = $this->_decoder->getElementContent();
 71:             if (!$this->_decoder->getElementEndTag() ||
 72:                 !$this->_decoder->getElementEndTag()) {
 73:                 return $this->_globalError(self::STATUS_PROTERROR);
 74:             }
 75:             if ($status == self::STATUS_CLIENT_SUCCESS) {
 76:                 $this->_state->setDeviceRWStatus($this->_devId, Horde_ActiveSync::RWSTATUS_WIPED);
 77:             }
 78: 
 79:             // Need to send *something* in the policytype field even if wiping
 80:             $policytype = self::POLICYTYPE_XML;
 81:         } else {
 82:             if (!$this->_decoder->getElementStartTag(Horde_ActiveSync::PROVISION_POLICIES) ||
 83:                 !$this->_decoder->getElementStartTag(Horde_ActiveSync::PROVISION_POLICY)) {
 84: 
 85:                 return $this->_globalError(self::STATUS_PROTERROR);
 86:             }
 87: 
 88:             // iOS (at least 5.0.1) incorrectly sends a STATUS tag before the
 89:             // REMOTEWIPE response.
 90:             if (!$this->_decoder->getElementStartTag(Horde_ActiveSync::PROVISION_POLICYTYPE)) {
 91:                 if ($this->_decoder->getElementStartTag(Horde_ActiveSync::PROVISION_STATUS)) {
 92:                     $this->_decoder->getElementContent();
 93:                     $this->_decoder->getElementEndTag(); // status
 94:                 }
 95:             } else {
 96:                 $policytype = $this->_decoder->getElementContent();
 97:                 if ($policytype != self::POLICYTYPE_XML) {
 98:                     $policyStatus = self::STATUS_POLICYUNKNOWN;
 99:                 }
100:                 if (!$this->_decoder->getElementEndTag()) {//policytype
101:                     return $this->_globalError(self::STATUS_PROTERROR);
102:                 }
103:             }
104: 
105:             // Check to be sure that we *need* to PROVISION
106:             if ($this->_provisioning === false) {
107:                 $this->_sendNoProvisionNeededResponse($status);
108:                 return true;
109:             }
110: 
111:             // POLICYKEY is only sent by client in phase 3
112:             if ($this->_decoder->getElementStartTag(Horde_ActiveSync::PROVISION_POLICYKEY)) {
113:                 $policykey = $this->_decoder->getElementContent();
114:                 $this->_logger->debug('[' . $this->_device->id .'] PHASE 3 policykey sent from PIM: ' . $policykey);
115:                 if (!$this->_decoder->getElementEndTag() ||
116:                     !$this->_decoder->getElementStartTag(Horde_ActiveSync::PROVISION_STATUS)) {
117: 
118:                     return $this->_globalError(self::STATUS_PROTERROR);
119:                 }
120:                 if ($this->_decoder->getElementContent() != self::STATUS_SUCCESS) {
121:                     $this->_logger->err('Policy not accepted by device: ' . $this->_device->id);
122: 
123:                     if ($this->_provisioning == Horde_ActiveSync::PROVISIONING_LOOSE) {
124:                         // Loose provisioning, don't error out, just don't reqiure provision.
125:                         $this->_sendNoProvisionNeededResponse($status);
126:                         return true;
127:                     }
128: 
129:                     $policyStatus = self::STATUS_POLICYCORRUPT;
130:                 }
131: 
132:                 if (!$this->_decoder->getElementEndTag()) {
133:                     return $this->_globalError(self::STATUS_PROTERROR);
134:                 }
135:                 $phase2 = false;
136:             }
137: 
138:             if (!$this->_decoder->getElementEndTag() ||
139:                 !$this->_decoder->getElementEndTag()) {
140: 
141:                 return $this->_globalError(self::STATUS_PROTERROR);
142:             }
143: 
144:             // Handle remote wipe for other devices
145:             if ($this->_decoder->getElementStartTag(Horde_ActiveSync::PROVISION_REMOTEWIPE)) {
146:                 if (!$this->_decoder->getElementStartTag(Horde_ActiveSync::PROVISION_STATUS)) {
147:                     return $this->_globalError(self::STATUS_PROTERROR);
148:                 }
149:                 $status = $this->_decoder->getElementContent();
150:                 if (!$this->_decoder->getElementEndTag() ||
151:                     !$this->_decoder->getElementEndTag()) {
152:                     return $this->_globalError(self::STATUS_PROTERROR);
153:                 }
154:                 if ($status == self::STATUS_CLIENT_SUCCESS) {
155:                     $this->_state->setDeviceRWStatus($this->_device->id, Horde_ActiveSync::RWSTATUS_WIPED);
156:                 }
157:             }
158:         }
159: 
160:         if (!$this->_decoder->getElementEndTag()) { //provision
161:             return $this->_globalError(self::STATUS_PROTERROR);
162:         }
163: 
164:         // Start handling request and sending output
165:         $this->_encoder->StartWBXML();
166: 
167:         // End of Phase 3 - We create the "final" policy key, store it, then
168:         // send it to the client.
169:         if (!$phase2) {
170:             // Verify intermediate key
171:             if ($this->_state->getPolicyKey($this->_device->id) != $policykey) {
172:                 $policyStatus = self::STATUS_POLKEYMISM;
173:             } else {
174:                 // Set the final key
175:                 $policykey = $this->_state->generatePolicyKey();
176:                 $this->_state->setPolicyKey($this->_device->id, $policykey);
177:                 $this->_state->setDeviceRWStatus($this->_device->id, Horde_ActiveSync::RWSTATUS_OK);
178:             }
179:             $this->_cleanUpAfterPairing();
180:         } elseif (empty($policykey)) {
181:             // This is phase2 - we need to set the intermediate key
182:             $policykey = $this->_state->generatePolicyKey();
183:             $this->_state->setPolicyKey($this->_device->id, $policykey);
184:         }
185: 
186:         $this->_encoder->startTag(Horde_ActiveSync::PROVISION_PROVISION);
187:         $this->_encoder->startTag(Horde_ActiveSync::PROVISION_STATUS);
188:         $this->_encoder->content($status);
189:         $this->_encoder->endTag();
190: 
191:         // Wipe data if status is pending or wiped
192:         $this->_encoder->startTag(Horde_ActiveSync::PROVISION_POLICIES);
193:         $this->_encoder->startTag(Horde_ActiveSync::PROVISION_POLICY);
194:         $this->_encoder->startTag(Horde_ActiveSync::PROVISION_POLICYTYPE);
195:         $this->_encoder->content($policytype);
196:         $this->_encoder->endTag();
197:         $this->_encoder->startTag(Horde_ActiveSync::PROVISION_STATUS);
198:         $this->_encoder->content($policyStatus);
199:         $this->_encoder->endTag();
200:         $this->_encoder->startTag(Horde_ActiveSync::PROVISION_POLICYKEY);
201:         $this->_encoder->content($policykey);
202:         $this->_encoder->endTag();
203: 
204:         // Send security policies - configure this/move to it's own method.
205:         if ($phase2 && $status == self::STATUS_SUCCESS && $policyStatus == self::STATUS_SUCCESS) {
206:             $this->_encoder->startTag(Horde_ActiveSync::PROVISION_DATA);
207:             if ($policytype == self::POLICYTYPE_XML) {
208:                 $this->_encoder->content($this->_driver->getCurrentPolicy(self::POLICYTYPE_XML));
209:             } else {
210:                 // TODO wbxml for 12.0
211:             }
212:             $this->_encoder->endTag(); //data
213:         }
214:         $this->_encoder->endTag();     //policy
215:         $this->_encoder->endTag();     //policies
216:         $rwstatus = $this->_state->getDeviceRWStatus($this->_device->id);
217:         if ($rwstatus == Horde_ActiveSync::RWSTATUS_PENDING || $rwstatus == Horde_ActiveSync::RWSTATUS_WIPED) {
218:             $this->_encoder->startTag(Horde_ActiveSync::PROVISION_REMOTEWIPE, false, true);
219:             $this->_state->setDeviceRWStatus($this->_device->id, Horde_ActiveSync::RWSTATUS_WIPED);
220:         }
221:         $this->_encoder->endTag();         //provision
222: 
223:         return true;
224:     }
225: 
226:     private function _sendNoProvisionNeededResponse($status)
227:     {
228:         $this->_encoder->startWBXML();
229:         $this->_encoder->startTag(Horde_ActiveSync::PROVISION_PROVISION);
230:         $this->_encoder->startTag(Horde_ActiveSync::PROVISION_STATUS);
231:         $this->_encoder->content($status);
232:         $this->_encoder->endTag();
233:         $this->_encoder->startTag(Horde_ActiveSync::PROVISION_POLICIES);
234:         $this->_encoder->startTag(Horde_ActiveSync::PROVISION_POLICY);
235:         $this->_encoder->startTag(Horde_ActiveSync::PROVISION_STATUS);
236:         $this->_encoder->content(self::STATUS_NOTDEFINED);
237:         $this->_encoder->endTag();
238:         $this->_encoder->endTag();
239:         $this->_encoder->endTag();
240:         $this->_encoder->endTag();
241:     }
242: 
243:     private function _globalError($status)
244:     {
245:         $this->_encoder->StartWBXML();
246:         $this->_encoder->startTag(Horde_ActiveSync::PROVISION_PROVISION);
247:         $this->_encoder->startTag(Horde_ActiveSync::PROVISION_STATUS);
248:         $this->_encoder->content($status);
249:         $this->_encoder->endTag();
250:         $this->_encoder->endTag();
251: 
252:         return false;
253:     }
254: 
255: }
API documentation generated by ApiGen