1<?php
2/***********************************************
3* File      :   provisioning.php
4* Project   :   Z-Push
5* Descr     :   Provides the PROVISIONING command
6*
7* Created   :   16.02.2012
8*
9* Copyright 2007 - 2016, 2015 Zarafa Deutschland GmbH
10*
11* This program is free software: you can redistribute it and/or modify
12* it under the terms of the GNU Affero General Public License, version 3,
13* as published by the Free Software Foundation.
14*
15* This program is distributed in the hope that it will be useful,
16* but WITHOUT ANY WARRANTY; without even the implied warranty of
17* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18* GNU Affero General Public License for more details.
19*
20* You should have received a copy of the GNU Affero General Public License
21* along with this program.  If not, see <http://www.gnu.org/licenses/>.
22*
23* Consult LICENSE file for details
24************************************************/
25
26class Provisioning extends RequestProcessor {
27
28    /**
29     * Handles the Provisioning command
30     *
31     * @param int       $commandCode
32     *
33     * @access public
34     * @return boolean
35     */
36    public function Handle($commandCode) {
37        $status = SYNC_PROVISION_STATUS_SUCCESS;
38        $policystatus = SYNC_PROVISION_POLICYSTATUS_SUCCESS;
39
40        $rwstatus = self::$deviceManager->GetProvisioningWipeStatus();
41        $rwstatusWiped = false;
42        $deviceInfoSet = false;
43
44        // if this is a regular provisioning require that an authenticated remote user
45        if ($rwstatus < SYNC_PROVISION_RWSTATUS_PENDING) {
46            ZLog::Write(LOGLEVEL_DEBUG, "RequestProcessor::HandleProvision(): Forcing delayed Authentication");
47            self::Authenticate();
48        }
49
50        $phase2 = true;
51
52        if(!self::$decoder->getElementStartTag(SYNC_PROVISION_PROVISION))
53            return false;
54
55        // Loop through Provision request tags. Possible are:
56        // - Remote Wipe
57        // - DeviceInformation
58        // - Policies
59        // Each of them should only be once per request.
60        WBXMLDecoder::ResetInWhile("provisioningMain");
61        while(WBXMLDecoder::InWhile("provisioningMain")) {
62            $requestName = "";
63            if (self::$decoder->getElementStartTag(SYNC_PROVISION_REMOTEWIPE)) {
64                $requestName = SYNC_PROVISION_REMOTEWIPE;
65            }
66            if (self::$decoder->getElementStartTag(SYNC_PROVISION_POLICIES)) {
67                $requestName = SYNC_PROVISION_POLICIES;
68            }
69            if (self::$decoder->getElementStartTag(SYNC_SETTINGS_DEVICEINFORMATION)) {
70                $requestName = SYNC_SETTINGS_DEVICEINFORMATION;
71            }
72
73            if (!$requestName)
74                break;
75
76                //set is available for OOF, device password and device information
77            switch ($requestName) {
78                case SYNC_PROVISION_REMOTEWIPE:
79                    if(!self::$decoder->getElementStartTag(SYNC_PROVISION_STATUS))
80                        return false;
81
82                    $instatus = self::$decoder->getElementContent();
83
84                    if(!self::$decoder->getElementEndTag())
85                        return false;
86
87                    if(!self::$decoder->getElementEndTag())
88                        return false;
89
90                    $phase2 = false;
91                    $rwstatusWiped = true;
92                    //TODO check - do it after while(1) finished?
93                    break;
94
95                case SYNC_PROVISION_POLICIES:
96                    if(!self::$decoder->getElementStartTag(SYNC_PROVISION_POLICY))
97                        return false;
98
99                    if(!self::$decoder->getElementStartTag(SYNC_PROVISION_POLICYTYPE))
100                        return false;
101
102                    $policytype = self::$decoder->getElementContent();
103                    if ($policytype != 'MS-WAP-Provisioning-XML' && $policytype != 'MS-EAS-Provisioning-WBXML') {
104                        $status = SYNC_PROVISION_STATUS_SERVERERROR;
105                    }
106                    if(!self::$decoder->getElementEndTag()) //policytype
107                        return false;
108
109                    if (self::$decoder->getElementStartTag(SYNC_PROVISION_POLICYKEY)) {
110                        $devpolicykey = self::$decoder->getElementContent();
111
112                        if(!self::$decoder->getElementEndTag())
113                            return false;
114
115                        if(!self::$decoder->getElementStartTag(SYNC_PROVISION_STATUS))
116                            return false;
117
118                        $instatus = self::$decoder->getElementContent();
119
120                        if(!self::$decoder->getElementEndTag())
121                            return false;
122
123                        $phase2 = false;
124                    }
125
126                    if(!self::$decoder->getElementEndTag()) //policy
127                        return false;
128
129                    if(!self::$decoder->getElementEndTag()) //policies
130                        return false;
131                    break;
132
133                case SYNC_SETTINGS_DEVICEINFORMATION:
134                    // AS14.1 and later clients pass Device Information on the initial Provision request
135                    if (!self::$decoder->getElementStartTag(SYNC_SETTINGS_SET))
136                        return false;
137                    $deviceInfoSet = true;
138                    $deviceinformation = new SyncDeviceInformation();
139                    $deviceinformation->Decode(self::$decoder);
140                    $deviceinformation->Status = SYNC_SETTINGSSTATUS_SUCCESS;
141                    self::$deviceManager->SaveDeviceInformation($deviceinformation);
142                    if (!self::$decoder->getElementEndTag())  // SYNC_SETTINGS_SET
143                        return false;
144                    if (!self::$decoder->getElementEndTag())  // SYNC_SETTINGS_DEVICEINFORMATION
145                        return false;
146                    break;
147
148                default:
149                    //TODO: a special status code needed?
150                    ZLog::Write(LOGLEVEL_WARN, sprintf ("This property ('%s') is not allowed to be used in a provision request", $requestName));
151            }
152
153        }
154
155        if(!self::$decoder->getElementEndTag()) //provision
156            return false;
157
158        if (PROVISIONING !== true) {
159            ZLog::Write(LOGLEVEL_INFO, "No policies deployed to device");
160            $policystatus = SYNC_PROVISION_POLICYSTATUS_NOPOLICY;
161        }
162
163        self::$encoder->StartWBXML();
164
165        //set the new final policy key in the device manager
166        // START ADDED dw2412 Android provisioning fix
167        if (!$phase2) {
168            $policykey = self::$deviceManager->GenerateProvisioningPolicyKey();
169            self::$deviceManager->SetProvisioningPolicyKey($policykey);
170            self::$topCollector->AnnounceInformation("Policies deployed", true);
171        }
172        else {
173            // just create a temporary key (i.e. iPhone OS4 Beta does not like policykey 0 in response)
174            $policykey = self::$deviceManager->GenerateProvisioningPolicyKey();
175        }
176        // END ADDED dw2412 Android provisioning fix
177
178        self::$encoder->startTag(SYNC_PROVISION_PROVISION);
179        {
180            self::$encoder->startTag(SYNC_PROVISION_STATUS);
181                self::$encoder->content($status);
182            self::$encoder->endTag();
183
184            if ($deviceInfoSet) {
185                self::$encoder->startTag(SYNC_SETTINGS_DEVICEINFORMATION);
186                    self::$encoder->startTag(SYNC_SETTINGS_STATUS);
187                    self::$encoder->content($deviceinformation->Status);
188                    self::$encoder->endTag(); //SYNC_SETTINGS_STATUS
189                self::$encoder->endTag(); //SYNC_SETTINGS_DEVICEINFORMATION
190            }
191
192            self::$encoder->startTag(SYNC_PROVISION_POLICIES);
193                self::$encoder->startTag(SYNC_PROVISION_POLICY);
194
195                if(isset($policytype)) {
196                    self::$encoder->startTag(SYNC_PROVISION_POLICYTYPE);
197                        self::$encoder->content($policytype);
198                    self::$encoder->endTag();
199                }
200
201                self::$encoder->startTag(SYNC_PROVISION_STATUS);
202                    self::$encoder->content($policystatus);
203                self::$encoder->endTag();
204
205                self::$encoder->startTag(SYNC_PROVISION_POLICYKEY);
206                       self::$encoder->content($policykey);
207                self::$encoder->endTag();
208
209                if ($phase2 && $policystatus === SYNC_PROVISION_POLICYSTATUS_SUCCESS) {
210                    self::$encoder->startTag(SYNC_PROVISION_DATA);
211                    if ($policytype == 'MS-WAP-Provisioning-XML') {
212                        self::$encoder->content('<wap-provisioningdoc><characteristic type="SecurityPolicy"><parm name="4131" value="1"/><parm name="4133" value="1"/></characteristic></wap-provisioningdoc>');
213                    }
214                    elseif ($policytype == 'MS-EAS-Provisioning-WBXML') {
215                        self::$encoder->startTag(SYNC_PROVISION_EASPROVISIONDOC);
216
217                            // get the provisioning object and log the loaded policy values
218                            $prov = self::$deviceManager->GetProvisioningObject(true);
219                            if (!$prov->Check())
220                                throw new FatalException("Invalid policies!");
221
222                            self::$deviceManager->SavePolicyHashAndName($prov);
223                            $prov->Encode(self::$encoder);
224                        self::$encoder->endTag();
225                    }
226                    else {
227                        ZLog::Write(LOGLEVEL_WARN, "Wrong policy type");
228                        self::$topCollector->AnnounceInformation("Policytype not supported", true);
229                        return false;
230                    }
231                    self::$topCollector->AnnounceInformation("Updated provisiong", true);
232
233                    self::$encoder->endTag();//data
234                }
235                self::$encoder->endTag();//policy
236            self::$encoder->endTag(); //policies
237        }
238
239        //wipe data if a higher RWSTATUS is requested
240        if ($rwstatus > SYNC_PROVISION_RWSTATUS_OK && $policystatus === SYNC_PROVISION_POLICYSTATUS_SUCCESS) {
241            self::$encoder->startTag(SYNC_PROVISION_REMOTEWIPE, false, true);
242            self::$deviceManager->SetProvisioningWipeStatus(($rwstatusWiped)?SYNC_PROVISION_RWSTATUS_WIPED:SYNC_PROVISION_RWSTATUS_REQUESTED);
243            self::$topCollector->AnnounceInformation(sprintf("Remote wipe %s", ($rwstatusWiped)?"executed":"requested"), true);
244        }
245
246        self::$encoder->endTag();//provision
247
248        return true;
249    }
250}
251