1: <?php
  2:   3:   4:   5:   6:   7:   8:   9:  10:  11:  12: 
 13: class Horde_Rpc_ActiveSync extends Horde_Rpc
 14: {
 15:      16:  17:  18:  19: 
 20:     private $_get;
 21: 
 22:      23:  24:  25:  26: 
 27:     private $_server;
 28: 
 29:      30:  31:  32:  33: 
 34:     private $_backend;
 35: 
 36:      37:  38:  39:  40:  41:  42:  43:  44:  45:  46: 
 47:     public function __construct(Horde_Controller_Request_Http $request, array $params = array())
 48:     {
 49:         parent::__construct($request, $params);
 50: 
 51:         
 52:         $this->_get = $request->getGetVars();
 53:         if ($request->getMethod() == 'POST' &&
 54:             (empty($this->_get['Cmd']) || empty($this->_get['DeviceId']) || empty($this->_get['DeviceType']))) {
 55: 
 56:             $this->_logger->err('Missing required parameters.');
 57:             throw new Horde_Rpc_Exception('Your device requested the ActiveSync URL wihtout required parameters.');
 58:         }
 59: 
 60:         
 61:         if ($request->getMethod() == 'POST' &&  empty($this->_get['User'])) {
 62:             $serverVars = $this->_request->getServerVars();
 63:             if ($serverVars['PHP_AUTH_USER']) {
 64:                 $this->_get['User'] = $serverVars['PHP_AUTH_USER'];
 65:             } elseif ($serverVars['Authorization']) {
 66:                 $hash = str_replace('Basic ', '', $serverVars['Authorization']);
 67:                 $hash = base64_decode($hash);
 68:                 if (strpos($hash, ':') !== false) {
 69:                     list($this->_get['User'], $pass) = explode(':', $hash, 2);
 70:                 }
 71:             }
 72:             if (empty($this->_get['User'])) {
 73:                 $this->_logger->err('Missing required parameters.');
 74:                 throw new Horde_Rpc_Exception('Your device requested the ActiveSync URL wihtout required parameters.');
 75:             }
 76:         }
 77: 
 78:         $this->_backend = $params['backend'];
 79:         $this->_server = $params['server'];
 80:         $this->_server->setProvisioning(empty($params['provisioning']) ? false : $params['provisioning']);
 81:     }
 82: 
 83:      84:  85:  86:  87: 
 88:     public function getResponseContentType()
 89:     {
 90:         return 'application/vnd.ms-sync.wbxml';
 91:     }
 92: 
 93:      94:  95:  96:  97:  98: 
 99:     public function getInput()
100:     {
101:         return null;
102:     }
103: 
104:     105: 106: 107: 108: 109: 110: 
111:     public function getResponse($request)
112:     {
113:         
114:         ob_start(null, 1048576);
115:         $serverVars = $this->_request->getServerVars();
116:         switch ($serverVars['REQUEST_METHOD']) {
117:         case 'OPTIONS':
118:         case 'GET':
119:             if ($serverVars['REQUEST_METHOD'] == 'GET' &&
120:                 $this->_get['Cmd'] != 'OPTIONS') {
121:                 throw new Horde_Rpc_Exception('Trying to access the ActiveSync endpoint from a browser. Not Supported.');
122:             }
123:             $this->_logger->debug('Horde_Rpc_ActiveSync::getResponse() starting for OPTIONS');
124:             try {
125:                 $this->_server->handleRequest('Options', null, null);
126:             } catch (Horde_ActiveSync_Exception $e) {
127:                 $this->_handleError($e);
128:             }
129:             break;
130: 
131:         case 'POST':
132:             Horde_ActiveSync::activeSyncHeader();
133:             $this->_logger->debug('Horde_Rpc_ActiveSync::getResponse() starting for ' . $this->_get['Cmd']);
134:             try {
135:                 $this->_server->handleRequest($this->_get['Cmd'], $this->_get['DeviceId']);
136:             } catch (Horde_ActiveSync_Exception $e) {
137:                 $this->_handleError($e);
138:             }
139:             break;
140:         }
141:     }
142: 
143:     144: 145: 146: 
147:     public function sendOutput($output)
148:     {
149:         
150:         
151:         
152:         
153:         
154:         
155:         $len = ob_get_length();
156:         $data = ob_get_contents();
157:         ob_end_clean();
158: 
159:         
160:         
161:         
162:         header('Content-Type: application/vnd.ms-sync.wbxml');
163:         header('Content-Length: ' . $len);
164:         echo $data;
165:     }
166: 
167:     168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 
180:     public function authorize()
181:     {
182:         $this->_logger->debug('Horde_Rpc_ActiveSync::authorize() starting');
183:         if (!$this->_requireAuthorization) {
184:             return true;
185:         }
186: 
187:         
188:         $serverVars = $this->_request->getServerVars();
189:         $user = $pass = '';
190:         if (!empty($serverVars['PHP_AUTH_USER'])) {
191:             $user = $serverVars['PHP_AUTH_USER'];
192:             $pass = $serverVars['PHP_AUTH_PW'];
193:         } elseif (!empty($serverVars['Authorization'])) {
194:             $hash = str_replace('Basic ', '', $serverVars['Authorization']);
195:             $hash = base64_decode($hash);
196:             if (strpos($hash, ':') !== false) {
197:                 list($user, $pass) = explode(':', $hash, 2);
198:             }
199:         }
200: 
201:         
202:         $pos = strrpos($user, '\\');
203:         if ($pos !== false) {
204:             $domain = substr($user, 0, $pos);
205:             $user = substr($user, $pos + 1);
206:         } else {
207:             $domain = null;
208:         }
209: 
210:         
211:         $results = $this->_backend->logon($user, $pass, $domain);
212:         if (!$results && empty($this->_policykey)) {
213:             header('HTTP/1.1 401 Unauthorized');
214:             header('WWW-Authenticate: Basic realm="Horde RPC"');
215:             $this->_logger->info('Access denied for user: ' . $user . '. Username or password incorrect.');
216:         }
217: 
218:         
219:         if (empty($this->_get['User'])) {
220:             return false;
221:         }
222:         $results = $this->_backend->setup($this->_get['User']);
223:         if (!$results) {
224:             header('HTTP/1.1 401 Unauthorized');
225:             header('WWW-Authenticate: Basic realm="Horde RPC"');
226:             echo 'Access denied or user ' . $this->_get['User'] . ' unknown.';
227:         }
228: 
229:         $this->_logger->debug('Horde_Rpc_ActiveSync::authorize() exiting');
230: 
231:         return true;
232:     }
233: 
234:     235: 236: 237: 238: 239: 240: 
241:     protected function _handleError($e)
242:     {
243:         $trace = $e->getTraceAsString();
244:         $m = $e->getMessage();
245:         $buffer = ob_get_clean();
246: 
247:         $this->_logger->err('Error in communicating with ActiveSync server: ' . $m);
248:         $this->_logger->err($trace);
249:         $this->_logger->err('Buffer contents: ' . $buffer);
250:         throw new Horde_Rpc_Exception($e);
251:     }
252: 
253: }
254: