Back to index

d-push  2.0
request.php
Go to the documentation of this file.
00001 <?php
00002 /***********************************************
00003 * File      :   request.php
00004 * Project   :   Z-Push
00005 * Descr     :   This class checks and processes
00006 *               all incoming data of the request.
00007 *
00008 * Created   :   01.10.2007
00009 *
00010 * Copyright 2007 - 2011 Zarafa Deutschland GmbH
00011 *
00012 * This program is free software: you can redistribute it and/or modify
00013 * it under the terms of the GNU Affero General Public License, version 3,
00014 * as published by the Free Software Foundation with the following additional
00015 * term according to sec. 7:
00016 *
00017 * According to sec. 7 of the GNU Affero General Public License, version 3,
00018 * the terms of the AGPL are supplemented with the following terms:
00019 *
00020 * "Zarafa" is a registered trademark of Zarafa B.V.
00021 * "Z-Push" is a registered trademark of Zarafa Deutschland GmbH
00022 * The licensing of the Program under the AGPL does not imply a trademark license.
00023 * Therefore any rights, title and interest in our trademarks remain entirely with us.
00024 *
00025 * However, if you propagate an unmodified version of the Program you are
00026 * allowed to use the term "Z-Push" to indicate that you distribute the Program.
00027 * Furthermore you may use our trademarks where it is necessary to indicate
00028 * the intended purpose of a product or service provided you use it in accordance
00029 * with honest practices in industrial or commercial matters.
00030 * If you want to propagate modified versions of the Program under the name "Z-Push",
00031 * you may only do so if you have a written permission by Zarafa Deutschland GmbH
00032 * (to acquire a permission please contact Zarafa at trademark@zarafa.com).
00033 *
00034 * This program is distributed in the hope that it will be useful,
00035 * but WITHOUT ANY WARRANTY; without even the implied warranty of
00036 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00037 * GNU Affero General Public License for more details.
00038 *
00039 * You should have received a copy of the GNU Affero General Public License
00040 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00041 *
00042 * Consult LICENSE file for details
00043 ************************************************/
00044 
00045 class Request {
00046     const UNKNOWN = "unknown";
00047 
00051     const LETTERS_ONLY = 1;
00052     const HEX_ONLY = 2;
00053     const WORDCHAR_ONLY = 3;
00054     const NUMBERS_ONLY = 4;
00055     const NUMBERSDOT_ONLY = 5;
00056     const HEX_EXTENDED = 6;
00057 
00061     const COMMANDPARAM_ATTACHMENTNAME = 0;
00062     const COMMANDPARAM_COLLECTIONID = 1; //deprecated
00063     const COMMANDPARAM_COLLECTIONNAME = 2; //deprecated
00064     const COMMANDPARAM_ITEMID = 3;
00065     const COMMANDPARAM_LONGID = 4;
00066     const COMMANDPARAM_PARENTID = 5; //deprecated
00067     const COMMANDPARAM_OCCURRENCE = 6;
00068     const COMMANDPARAM_OPTIONS = 7; //used by SmartReply, SmartForward, SendMail, ItemOperations
00069     const COMMANDPARAM_USER = 8; //used by any command
00070     //possible bitflags for COMMANDPARAM_OPTIONS
00071     const COMMANDPARAM_OPTIONS_SAVEINSENT = 0x01;
00072     const COMMANDPARAM_OPTIONS_ACCEPTMULTIPART = 0x02;
00073 
00074     static private $input;
00075     static private $output;
00076     static private $headers;
00077     static private $getparameters;
00078     static private $command;
00079     static private $device;
00080     static private $method;
00081     static private $remoteAddr;
00082     static private $getUser;
00083     static private $devid;
00084     static private $devtype;
00085     static private $authUser;
00086     static private $authDomain;
00087     static private $authPassword;
00088     static private $asProtocolVersion;
00089     static private $policykey;
00090     static private $useragent;
00091     static private $attachmentName;
00092     static private $collectionId;
00093     static private $itemId;
00094     static private $longId; //TODO
00095     static private $occurence; //TODO
00096     static private $saveInSent;
00097 
00098 
00105     static public function Initialize() {
00106         // try to open stdin & stdout
00107         self::$input = fopen("php://input", "r");
00108         self::$output = fopen("php://output", "w+");
00109 
00110         // Parse the standard GET parameters
00111         if(isset($_GET["Cmd"]))
00112             self::$command = self::filterEvilInput($_GET["Cmd"], self::LETTERS_ONLY);
00113 
00114         // getUser is unfiltered, as everything is allowed.. even "/", "\" or ".."
00115         if(isset($_GET["User"]))
00116             self::$getUser = $_GET["User"];
00117         if(isset($_GET["DeviceId"]))
00118             self::$devid = self::filterEvilInput($_GET["DeviceId"], self::WORDCHAR_ONLY);
00119         if(isset($_GET["DeviceType"]))
00120             self::$devtype = self::filterEvilInput($_GET["DeviceType"], self::LETTERS_ONLY);
00121         if (isset($_GET["AttachmentName"]))
00122             self::$attachmentName = self::filterEvilInput($_GET["AttachmentName"], self::HEX_EXTENDED);
00123         if (isset($_GET["CollectionId"]))
00124             self::$collectionId = self::filterEvilInput($_GET["CollectionId"], self::HEX_ONLY);
00125         if (isset($_GET["ItemId"]))
00126             self::$itemId = self::filterEvilInput($_GET["ItemId"], self::HEX_ONLY);
00127         if (isset($_GET["SaveInSent"]) && $_GET["SaveInSent"] == "T")
00128             self::$saveInSent = true;
00129 
00130         if(isset($_SERVER["REQUEST_METHOD"]))
00131             self::$method = self::filterEvilInput($_SERVER["REQUEST_METHOD"], self::LETTERS_ONLY);
00132         // TODO check IPv6 addresses
00133         if(isset($_SERVER["REMOTE_ADDR"]))
00134             self::$remoteAddr = self::filterEvilInput($_SERVER["REMOTE_ADDR"], self::NUMBERSDOT_ONLY);
00135 
00136         // in protocol version > 14 mobile send these inputs as encoded query string
00137         if (!isset(self::$command) && !empty($_SERVER['QUERY_STRING']) && Utils::IsBase64String($_SERVER['QUERY_STRING'])) {
00138             $query = Utils::DecodeBase64URI($_SERVER['QUERY_STRING']);
00139             if (!isset(self::$command) && isset($query['Command']))
00140                 self::$command = Utils::GetCommandFromCode($query['Command']);
00141 
00142             if (!isset(self::$getUser) && isset($query[self::COMMANDPARAM_USER]))
00143                 self::$getUser = $query[self::COMMANDPARAM_USER];
00144 
00145             if (!isset(self::$devid) && isset($query['DevID']))
00146                 self::$devid = self::filterEvilInput($query['DevID'], self::WORDCHAR_ONLY);
00147 
00148             if (!isset(self::$devtype) && isset($query['DevType']))
00149                 self::$devtype = self::filterEvilInput($query['DevType'], self::LETTERS_ONLY);
00150 
00151             if (isset($query['PolKey']))
00152                 self::$policykey = (int) self::filterEvilInput($query['PolKey'], self::NUMBERS_ONLY);
00153 
00154             if (isset($query['ProtVer']))
00155                 self::$asProtocolVersion = self::filterEvilInput($query['ProtVer'], self::NUMBERS_ONLY) / 10;
00156 
00157             if (isset($query[self::COMMANDPARAM_ATTACHMENTNAME]))
00158                 self::$attachmentName = self::filterEvilInput($query[self::COMMANDPARAM_ATTACHMENTNAME], self::HEX_EXTENDED);
00159 
00160             if (isset($query[self::COMMANDPARAM_COLLECTIONID]))
00161                 self::$collectionId = self::filterEvilInput($query[self::COMMANDPARAM_COLLECTIONID], self::HEX_ONLY);
00162 
00163             if (isset($query[self::COMMANDPARAM_ITEMID]))
00164                 self::$itemId = self::filterEvilInput($query[self::COMMANDPARAM_ITEMID], self::HEX_ONLY);
00165 
00166             if (isset($query[self::COMMANDPARAM_OPTIONS]) && ($query[self::COMMANDPARAM_OPTIONS] & 1))
00167                 self::$saveInSent = true;
00168         }
00169 
00170         // in base64 encoded query string user is not necessarily set
00171         if (!isset(self::$getUser) && isset($_SERVER['PHP_AUTH_USER']))
00172             list(self::$getUser,) = Utils::SplitDomainUser($_SERVER['PHP_AUTH_USER']);
00173     }
00174 
00181     static public function ProcessHeaders() {
00182         self::$headers = array_change_key_case(apache_request_headers(), CASE_LOWER);
00183         self::$useragent = (isset(self::$headers["user-agent"]))? self::$headers["user-agent"] : self::UNKNOWN;
00184         if (!isset(self::$asProtocolVersion))
00185             self::$asProtocolVersion = (isset(self::$headers["ms-asprotocolversion"]))? self::filterEvilInput(self::$headers["ms-asprotocolversion"], self::NUMBERSDOT_ONLY) : ZPush::GetLatestSupportedASVersion();
00186 
00187         //if policykey is not yet set, try to set it from the header
00188         //the policy key might be set in Request::Initialize from the base64 encoded query
00189         if (!isset(self::$policykey)) {
00190             if (isset(self::$headers["x-ms-policykey"]))
00191                 self::$policykey = (int) self::filterEvilInput(self::$headers["x-ms-policykey"], self::NUMBERS_ONLY);
00192             else
00193                 self::$policykey = 0;
00194         }
00195 
00196         if (!empty($_SERVER['QUERY_STRING']) && Utils::IsBase64String($_SERVER['QUERY_STRING'])) {
00197             ZLog::Write(LOGLEVEL_DEBUG, "Using data from base64 encoded query string");
00198             if (isset(self::$policykey))
00199                 self::$headers["x-ms-policykey"] = self::$policykey;
00200 
00201             if (isset(self::$asProtocolVersion))
00202                 self::$headers["ms-asprotocolversion"] = self::$asProtocolVersion;
00203         }
00204         ZLog::Write(LOGLEVEL_DEBUG, sprintf("Request::ProcessHeaders() ASVersion: %s", self::$asProtocolVersion));
00205     }
00206 
00213     static public function AuthenticationInfo() {
00214         // split username & domain if received as one
00215         if (isset($_SERVER['PHP_AUTH_USER'])) {
00216             list(self::$authUser, self::$authDomain) = Utils::SplitDomainUser($_SERVER['PHP_AUTH_USER']);
00217             self::$authPassword = (isset($_SERVER['PHP_AUTH_PW']))?$_SERVER['PHP_AUTH_PW'] : "";
00218         }
00219         // authUser & authPassword are unfiltered!
00220         return (self::$authUser != "" && self::$authPassword != "");
00221     }
00222 
00223 
00234     static public function GetInputStream() {
00235         if (isset(self::$input))
00236             return self::$input;
00237         else
00238             return false;
00239     }
00240 
00247     static public function GetOutputStream() {
00248         if (isset(self::$output))
00249             return self::$output;
00250         else
00251             return false;
00252     }
00253 
00260     static public function GetMethod() {
00261         if (isset(self::$method))
00262             return self::$method;
00263         else
00264             return self::UNKNOWN;
00265     }
00266 
00273     static public function GetGETUser() {
00274         if (isset(self::$getUser))
00275             return self::$getUser;
00276         else
00277             return self::UNKNOWN;
00278     }
00279 
00286     static public function GetGETItemId() {
00287         if (isset(self::$itemId))
00288             return self::$itemId;
00289         else
00290             return false;
00291         }
00292 
00299     static public function GetGETCollectionId() {
00300         if (isset(self::$collectionId))
00301             return self::$collectionId;
00302         else
00303             return false;
00304     }
00305 
00312     static public function GetGETSaveInSent() {
00313         if (isset(self::$saveInSent))
00314             return self::$saveInSent;
00315         else
00316             return true;
00317     }
00318 
00325     static public function GetGETAttachmentName() {
00326         if (isset(self::$attachmentName))
00327             return self::$attachmentName;
00328         else
00329             return false;
00330     }
00331 
00338     static public function GetAuthUser() {
00339         if (isset(self::$authUser))
00340             return self::$authUser;
00341         else
00342             return false;
00343     }
00344 
00351     static public function GetAuthDomain() {
00352         if (isset(self::$authDomain))
00353             return self::$authDomain;
00354         else
00355             return false;
00356     }
00357 
00364     static public function GetAuthPassword() {
00365         if (isset(self::$authPassword))
00366             return self::$authPassword;
00367         else
00368             return false;
00369     }
00370 
00377     static public function GetRemoteAddr() {
00378         if (isset(self::$remoteAddr))
00379             return self::$remoteAddr;
00380         else
00381             return "UNKNOWN";
00382     }
00383 
00390     static public function GetCommand() {
00391         if (isset(self::$command))
00392             return self::$command;
00393         else
00394             return false;
00395     }
00396 
00403     static public function GetCommandCode() {
00404         if (isset(self::$command))
00405             return Utils::GetCodeFromCommand(self::$command);
00406         else
00407             return false;
00408     }
00409 
00416     static public function GetDeviceID() {
00417         if (isset(self::$devid))
00418             return self::$devid;
00419         else
00420             return false;
00421     }
00422 
00429     static public function GetDeviceType() {
00430         if (isset(self::$devtype))
00431             return self::$devtype;
00432         else
00433             return false;
00434     }
00435 
00442     static public function GetProtocolVersion() {
00443         if (isset(self::$asProtocolVersion))
00444             return self::$asProtocolVersion;
00445         else
00446             return false;
00447     }
00448 
00455     static public function GetUserAgent() {
00456         if (isset(self::$useragent))
00457             return self::$useragent;
00458         else
00459             return self::UNKNOWN;
00460     }
00461 
00468     static public function GetPolicyKey() {
00469         if (isset(self::$policykey))
00470             return self::$policykey;
00471         else
00472             return false;
00473     }
00474 
00481     static public function WasPolicyKeySent() {
00482         return isset(self::$headers["x-ms-policykey"]);
00483     }
00484 
00491     static public function IsMethodPOST() {
00492         return (self::$method == "POST");
00493     }
00494 
00501     static public function IsMethodGET() {
00502         return (self::$method == "GET");
00503     }
00504 
00511     static public function IsMethodOPTIONS() {
00512         return (self::$method == "OPTIONS");
00513     }
00514 
00522     static public function IsValidDeviceID() {
00523         if (self::GetDeviceID() === "validate" || self::GetDeviceID() === "webservice")
00524             return false;
00525         else
00526             return true;
00527     }
00528 
00535     static public function GetContentLength() {
00536         return (isset(self::$headers["content-length"]))? (int) self::$headers["content-length"] : 0;
00537     }
00538 
00539 
00554     static private function filterEvilInput($input, $filter, $replacevalue = '') {
00555         $re = false;
00556         if ($filter == self::LETTERS_ONLY)            $re = "/[^A-Za-z]/";
00557         else if ($filter == self::HEX_ONLY)           $re = "/[^A-Fa-f0-9]/";
00558         else if ($filter == self::WORDCHAR_ONLY)      $re = "/[^A-Za-z0-9]/";
00559         else if ($filter == self::NUMBERS_ONLY)       $re = "/[^0-9]/";
00560         else if ($filter == self::NUMBERSDOT_ONLY)    $re = "/[^0-9\.]/";
00561         else if ($filter == self::HEX_EXTENDED)       $re = "/[^A-Fa-f0-9\:]/";
00562 
00563         return ($re) ? preg_replace($re, $replacevalue, $input) : '';
00564     }
00565 }
00566 ?>