1<?php 2/** 3 * Horde_ActiveSync_Policies:: 4 * 5 * @license http://www.horde.org/licenses/gpl GPLv2 6 * 7 * @copyright 2010-2020 Horde LLC (http://www.horde.org) 8 * @author Michael J Rubinsky <mrubinsk@horde.org> 9 * @package ActiveSync 10 */ 11/** 12 * Horde_ActiveSync_Policies:: Wraps all functionality related to generating 13 * the XML or WBXML for EAS Policies. 14 * 15 * @license http://www.horde.org/licenses/gpl GPLv2 16 * 17 * @copyright 2010-2020 Horde LLC (http://www.horde.org) 18 * @author Michael J Rubinsky <mrubinsk@horde.org> 19 * @package ActiveSync 20 */ 21class Horde_ActiveSync_Policies 22{ 23 /* Policy configuration keys */ 24 const POLICY_PIN = 'DevicePasswordEnabled'; 25 const POLICY_AEFVALUE = 'MaxInactivityTimeDeviceLock'; 26 const POLICY_CODEFREQ = 'codewordfrequency'; 27 const POLICY_MINLENGTH = 'MinDevicePasswordLength'; 28 const POLICY_COMPLEXITY = 'AlphanumericDevicePasswordRequired'; 29 // 12.0 30 //const POLICY_PWDRECOVERY = 'passwordrecovery'; 31 //const POLICY_PWDEXPIRATION = 'passwordexpiration'; 32 //const POLICY_PWDHISTORY = 'passwordhistory'; 33 const POLICY_ENCRYPTION = 'DeviceEncryptionEnabled'; 34 const POLICY_ATC = 'AttachmentsEnabled'; 35 const POLICY_MAXATCSIZE = 'MaxAttachmentSize'; 36 const POLICY_MAXFAILEDATTEMPTS = 'MaxDevicePasswordFailedAttempts'; 37 // 12.1 38 const POLICY_ALLOW_SDCARD = 'AllowStorageCard'; 39 const POLICY_ALLOW_CAMERA = 'AllowCamera'; 40 const POLICY_ALLOW_SMS = 'AllowTextMessaging'; 41 const POLICY_ALLOW_WIFI = 'AllowWiFi'; 42 const POLICY_ALLOW_BLUETOOTH = 'AllowBluetooth'; 43 const POLICY_ALLOW_POPIMAP = 'AllowPOPIMAPEmail'; 44 const POLICY_ALLOW_BROWSER = 'AllowBrowser'; 45 const POLICY_REQUIRE_SMIME_SIGNED = 'RequireSignedSMIMEMessages'; 46 const POLICY_REQUIRE_SMIME_ENCRYPTED = 'RequireEncryptedSMIMEMessages'; 47 const POLICY_DEVICE_ENCRYPTION = 'RequireDeviceEncryption'; 48 const POLICY_ALLOW_HTML = 'AllowHTMLEmail'; 49 const POLICY_MAX_EMAIL_AGE = 'MaxEmailAgeFilter'; 50 //const POLICY_MAX_EMAIL_TRUNCATION = 'maxemailtruncation'; 51 //const POLICY_MAX_HTMLEMAIL_TRUNCATION = 'maxhtmlemailtruncation'; 52 const POLICY_ROAMING_NOPUSH = 'RequireManualSyncWhenRoaming'; 53 54 /** 55 * Default policy values used in both 12.0 and 12.1 56 * 57 * @var array 58 */ 59 protected $_defaults = array( 60 self::POLICY_PIN => false, 61 self::POLICY_AEFVALUE => '0', 62 self::POLICY_MAXFAILEDATTEMPTS => '5', 63 self::POLICY_CODEFREQ => '0', 64 self::POLICY_MINLENGTH => '5', 65 ); 66 67 /** 68 * Deafaults for 12.0 policies. 69 * 70 * @var array 71 */ 72 protected $_defaults_twelve = array( 73 self::POLICY_ATC => '1', 74 self::POLICY_ENCRYPTION => '0', 75 self::POLICY_MAXATCSIZE => '5000000', 76 self::POLICY_COMPLEXITY => '0', 77 //self::POLICY_PWDRECOVERY => '0', 78 //self::POLICY_PWDEXPIRATION => '0', 79 //self::POLICY_PWDHISTORY => '0', 80 ); 81 82 /** 83 * Defaults used only in 12.1 84 * 85 * @var array 86 */ 87 protected $_defaults_twelveone = array( 88 // 1 == Allow/Yes, 0 == Disallow/No. 89 self::POLICY_ALLOW_SDCARD => '1', 90 self::POLICY_ALLOW_CAMERA => '1', 91 self::POLICY_ALLOW_SMS => '1', 92 self::POLICY_ALLOW_WIFI => '1', 93 self::POLICY_ALLOW_BLUETOOTH => '1', 94 self::POLICY_ALLOW_POPIMAP => '1', 95 self::POLICY_ALLOW_BROWSER => '1', 96 self::POLICY_REQUIRE_SMIME_ENCRYPTED => '0', 97 self::POLICY_REQUIRE_SMIME_SIGNED => '0', 98 self::POLICY_DEVICE_ENCRYPTION => '0', 99 self::POLICY_ALLOW_HTML => '1', 100 self::POLICY_MAX_EMAIL_AGE => '0', 101 self::POLICY_ROAMING_NOPUSH => '0', 102 ); 103 104 /** 105 * Explicitly set policies. 106 * 107 * @var array 108 */ 109 protected $_overrides; 110 111 /** 112 * Output stream 113 * 114 * @var Horde_ActiveSync_Wbxml_Encoder 115 */ 116 protected $_encoder; 117 118 /** 119 * EAS version to support. 120 * 121 * @var long 122 */ 123 protected $_version; 124 125 /** 126 * Local cache of all policies to send. 127 * 128 * @var array 129 */ 130 protected $_policies = array(); 131 132 /** 133 * Const'r 134 * 135 * @param Horde_ActiveSync_Wbxml_Encoder $encoder The output stream encoder 136 * @param float $version The EAS Version. 137 * @param array $policies The policy array. 138 */ 139 public function __construct( 140 Horde_ActiveSync_Wbxml_Encoder $encoder = null, 141 $version = Horde_ActiveSync::VERSION_TWELVEONE, 142 array $policies = array()) 143 { 144 $this->_encoder = $encoder; 145 if ($version >= Horde_ActiveSync::VERSION_TWELVE) { 146 $this->_defaults = array_merge($this->_defaults, $this->_defaults_twelve); 147 } 148 if ($version >= Horde_ActiveSync::VERSION_TWELVEONE) { 149 $this->_defaults = array_merge($this->_defaults, $this->_defaults_twelveone); 150 } 151 152 $this->_version = $version; 153 $this->_overrides = $policies; 154 } 155 156 /** 157 * Return a list of all configurable policy names. 158 * 159 * @return array 160 */ 161 public function getAvailablePolicies() 162 { 163 return array_keys($this->_defaults); 164 } 165 166 /** 167 * Determine if the requested policy settings are available for the current 168 * version being used. 169 * 170 * @return boolean True if policies are available in current version, false 171 * otherwise. 172 */ 173 public function validatePolicyVersion() 174 { 175 $policies = $this->_getPolicies(); 176 177 // Validate the version against the required policies. 178 if ($this->_version < Horde_ActiveSync::VERSION_TWELVEONE) { 179 foreach ($policies as $key => $value) { 180 if (!empty($this->_defaults_twelveone[$key]) && 181 $this->_defaults_twelveone[$key] != $value) { 182 183 return false; 184 } 185 } 186 } 187 188 return true; 189 } 190 191 /** 192 * Output the policies as XML. Only used in EAS Version 2.5. This method 193 * only outputs the 2.5 compatible policies. 194 * 195 * @throws Horde_ActiveSync_Exception 196 */ 197 public function toXml() 198 { 199 if (empty($this->_encoder)) { 200 throw new Horde_ActiveSync_Exception('No output stream'); 201 } 202 203 $policies = array_merge($this->_defaults, $this->_overrides); 204 205 $xml = '<wap-provisioningdoc><characteristic type="SecurityPolicy">' 206 . '<parm name="4131" value="' . ($policies[self::POLICY_PIN] ? 0 : 1) . '"/>' 207 . '</characteristic>'; 208 if ($policies[self::POLICY_PIN]) { 209 $xml .= '<characteristic type="Registry">' 210 . '<characteristic type="HKLM\Comm\Security\Policy\LASSD\AE\{50C13377-C66D-400C-889E-C316FC4AB374}">' 211 . '<parm name="AEFrequencyType" value="' . (!empty($policies[self::POLICY_AEFVALUE]) ? 1 : 0) . '"/>' 212 . (!empty($policies[self::POLICY_AEFVALUE]) ? '<parm name="AEFrequencyValue" value="' . $policies[self::POLICY_AEFVALUE] . '"/>' : '') 213 . '</characteristic>'; 214 215 if (!empty($policies[self::POLICY_MAXFAILEDATTEMPTS])) { 216 $xml .= '<characteristic type="HKLM\Comm\Security\Policy\LASSD"><parm name="DeviceWipeThreshold" value="' . $policies[self::POLICY_MAXFAILEDATTEMPTS] . '"/></characteristic>'; 217 } 218 if (!empty($policies[self::POLICY_CODEFREQ])) { 219 $xml .= '<characteristic type="HKLM\Comm\Security\Policy\LASSD"><parm name="CodewordFrequency" value="' . $policies[self::POLICY_CODEFREQ] . '"/></characteristic>'; 220 } 221 if (!empty($policies[self::POLICY_MINLENGTH])) { 222 $xml .= '<characteristic type="HKLM\Comm\Security\Policy\LASSD\LAP\lap_pw"><parm name="MinimumPasswordLength" value="' . $policies[self::POLICY_MINLENGTH] . '"/></characteristic>'; 223 } 224 if ($policies[self::POLICY_COMPLEXITY] !== false) { 225 $xml .= '<characteristic type="HKLM\Comm\Security\Policy\LASSD\LAP\lap_pw"><parm name="PasswordComplexity" value="' . $policies[self::POLICY_COMPLEXITY] . '"/></characteristic>'; 226 } 227 $xml .= '</characteristic>'; 228 } 229 $xml .= '</wap-provisioningdoc>'; 230 231 $this->_encoder->content($xml); 232 } 233 234 235 /** 236 * Output the policies as WBXML. Used in EAS Versions >= 12.0 237 */ 238 public function toWbxml() 239 { 240 if (empty($this->_encoder)) { 241 throw new Horde_ActiveSync_Exception('No output stream'); 242 } 243 244 $policies = $this->_getPolicies(); 245 246 $this->_encoder->startTag('Provision:EASProvisionDoc'); 247 248 $this->_sendPolicy(self::POLICY_PIN, $policies[self::POLICY_PIN] ? '1' : '0'); 249 if ($policies[self::POLICY_PIN]) { 250 $this->_sendPolicy(self::POLICY_COMPLEXITY, $policies[self::POLICY_COMPLEXITY], true); 251 $this->_sendPolicy(self::POLICY_MINLENGTH, $policies[self::POLICY_MINLENGTH], true); 252 $this->_sendPolicy(self::POLICY_MAXFAILEDATTEMPTS, $policies[self::POLICY_MAXFAILEDATTEMPTS], true); 253 $this->_sendPolicy(self::POLICY_COMPLEXITY, $policies[self::POLICY_COMPLEXITY] >= 1 ? '1' : '0', true); 254 } 255 $this->_sendPolicy(self::POLICY_ENCRYPTION, $policies[self::POLICY_ENCRYPTION], true); 256 $this->_sendPolicy(self::POLICY_ATC, $policies[self::POLICY_ATC], false); 257 $this->_sendPolicy(self::POLICY_AEFVALUE, $policies[self::POLICY_AEFVALUE], true); 258 $this->_sendPolicy(self::POLICY_MAXATCSIZE, $policies[self::POLICY_MAXATCSIZE], true); 259 if ($this->_version > Horde_ActiveSync::VERSION_TWELVE) { 260 $this->_sendPolicy(self::POLICY_ALLOW_SDCARD, $policies[self::POLICY_ALLOW_SDCARD], true); 261 $this->_sendPolicy(self::POLICY_ALLOW_CAMERA, $policies[self::POLICY_ALLOW_CAMERA], true); 262 $this->_sendPolicy(self::POLICY_DEVICE_ENCRYPTION, $policies[self::POLICY_DEVICE_ENCRYPTION], true); 263 $this->_sendPolicy(self::POLICY_ALLOW_WIFI, $policies[self::POLICY_ALLOW_WIFI], true); 264 $this->_sendPolicy(self::POLICY_ALLOW_SMS, $policies[self::POLICY_ALLOW_SMS], true); 265 $this->_sendPolicy(self::POLICY_ALLOW_POPIMAP, $policies[self::POLICY_ALLOW_POPIMAP], true); 266 $this->_sendPolicy(self::POLICY_ALLOW_BLUETOOTH, $policies[self::POLICY_ALLOW_BLUETOOTH], true); 267 $this->_sendPolicy(self::POLICY_ROAMING_NOPUSH, $policies[self::POLICY_ROAMING_NOPUSH], true); 268 $this->_sendPolicy(self::POLICY_ALLOW_HTML, $policies[self::POLICY_ALLOW_HTML], true); 269 $this->_sendPolicy(self::POLICY_MAX_EMAIL_AGE, $policies[self::POLICY_MAX_EMAIL_AGE], true); 270 $this->_sendPolicy(self::POLICY_REQUIRE_SMIME_SIGNED, $policies[self::POLICY_REQUIRE_SMIME_SIGNED], true); 271 $this->_sendPolicy(self::POLICY_REQUIRE_SMIME_ENCRYPTED, $policies[self::POLICY_REQUIRE_SMIME_ENCRYPTED], true); 272 $this->_sendPolicy(self::POLICY_ALLOW_BROWSER, $policies[self::POLICY_ALLOW_BROWSER], true); 273 } 274 275 $this->_encoder->endTag(); 276 } 277 278 /** 279 * Output a single policy value 280 * 281 * @param string $policy The policy name 282 * @param mixed $value The policy value 283 * @param boolean $nodefault Don't send the policy if the value is default. 284 */ 285 protected function _sendPolicy($policy, $value, $nodefault = false) 286 { 287 if ($nodefault && $value == $this->_defaults[$policy]) { 288 return; 289 } 290 if ($value === false) { 291 $value = 0; 292 } elseif ($value === true) { 293 $value = 1; 294 } 295 $this->_encoder->startTag('Provision:' . $policy); 296 $this->_encoder->content($value); 297 $this->_encoder->endTag(); 298 } 299 300 protected function _getPolicies() 301 { 302 if (empty($this->_policies)) { 303 $this->_policies = array_merge($this->_defaults, $this->_overrides); 304 } 305 306 return $this->_policies; 307 } 308 309} 310