* * Copyright (C) 2003 Miles Lott * * -------------------------------------------------------------------------* * This library is free software; you can redistribute it and/or modify it * * under the terms of the GNU Lesser General Public License as published by * * the Free Software Foundation; either version 2.1 of the License, * * or any later version. * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * * along with this library; if not, write to the Free Software Foundation, * * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * \**************************************************************************/ /* $Id$ */ class xmlrpc_server { var $server = ''; var $authed = True; var $log = False; //'/tmp/xmlrpc.log'; var $last_method = ''; function xmlrpc_server($dispMap='', $serviceNow=0) { $this->server = xmlrpc_server_create(); if($dispMap) { $this->dmap = $dispMap; if($serviceNow) { $this->service(); } } } function serializeDebug() { } function service($r = False) { if (!$r) // do we have a response, or we need to parse the request { $r = $this->parseRequest(); } if(!$r) { header('WWW-Authenticate: Basic realm="eGroupWare xmlrpc"'); header('HTTP/1.0 401 Unauthorized'); // for the log: $payload = "WWW-Authenticate: Basic realm=\"eGroupWare xmlrpc\"\nHTTP/1.0 401 Unauthorized\n"; echo $payload; } else { // $payload = '' . "\n" . $this->serializeDebug() . $r->serialize(); // Header("Content-type: text/xml\r\nContent-length: " . strlen($payload)); // print $payload; echo $r; } if($this->log) { $fp = fopen($this->log,'a+'); fwrite($fp,"\n\n" . date('Y-m-d H:i:s') . " authorized=" . ($this->authed ? $GLOBALS['phpgw_info']['user']['account_lid'] : 'False') . ", method='$this->last_method'\n"); fwrite($fp,"==== GOT ============================\n" . $GLOBALS['HTTP_RAW_POST_DATA'] . "\n==== RETURNED =======================\n"); fputs($fp,$payload); fclose($fp); } if($this->debug) { $this->echoInput(); $fp = fopen('/tmp/xmlrpc_debug.out','a+'); fputs($fp,$payload); fclose($fp); } } function add_to_map($methodname,$function,$sig,$doc) { xmlrpc_server_register_method($this->server,$methodname,$function); // xmlrpc_server_register_method($this->server,$methodname,'xmlrpc_call_wrapper'); // $descr = array( // 'function' => $function, // 'signature' => $sig, // 'docstring' => $doc // ); // xmlrpc_server_set_method_description($this->server,$methodname,$descr); $this->dmap[$methodname] = array( 'function' => $function, 'signature' => $sig, 'docstring' => $doc ); } function verifySignature($in, $sig) { return array(1); for($i=0; $igetNumParams()+1) { $itsOK = 1; for($n=0; $n<$in->getNumParams(); $n++) { $p = $in->getParam($n); // print "\n"; if ($p->kindOf() == 'scalar') { $pt = $p->scalartyp(); } else { $pt = $p->kindOf(); } // $n+1 as first type of sig is return type if ($pt != $cursig[$n+1]) { $itsOK = 0; $pno = $n+1; $wanted = $cursig[$n+1]; $got = $pt; break; } } if ($itsOK) { return array(1); } } } return array(0, "Wanted $wanted, got $got at param $pno)"); } function parseRequest($data='') { global $HTTP_RAW_POST_DATA; if($data == '') { $data = $HTTP_RAW_POST_DATA; } // return $this->echoInput($data); /* Decode to extract methodName */ $params = xmlrpc_decode_request($data, &$methName); $this->last_method = $methName; $syscall = 0; /* Setup dispatch map based on the function, if this is a system call */ if(ereg('^system\.', $methName)) { foreach($GLOBALS['_xmlrpcs_dmap'] as $meth => $dat) { $this->add_to_map($meth,$dat['function'],$dat['signature'],$dat['docstring']); } $sysCall = 1; $dmap = $this->dmap; } elseif(ereg('^examples\.',$methName) || ereg('^validator1\.',$methName) || ereg('^interopEchoTests\.', $methName) ) { $dmap = $this->dmap; $sysCall = 1; } /* verify dispatch map, or try to fix it for non-trivial system calls */ if(!isset($this->dmap[$methName]['function'])) { if($sysCall) { /* Bad or non-existent system call, return error */ $r = CreateObject('phpgwapi.xmlrpcresp', '', $GLOBALS['xmlrpcerr']['unknown_method'], $GLOBALS['xmlrpcstr']['unknown_method'] . ': ' . $methName ); return $r; } if($this->authed) { $method = $methName; list($app,$class,$method) = explode('.',$methName); switch($app) { case 'server': case 'phpgwapi': /* Server role functions only - api access */ if($GLOBALS['phpgw']->acl->get_role() >= PHPGW_ACL_SERVER) { $dmap = ExecMethod(sprintf('%s.%s.%s','phpgwapi',$class,'list_methods'),'xmlrpc'); } break; case 'service': /* Service functions, user-level */ $t = 'phpgwapi.' . $class . '.exec'; $dmap = ExecMethod($t,array($service,'list_methods','xmlrpc')); break; default: /* User-level application access */ if($GLOBALS['phpgw']->acl->check('run',PHPGW_ACL_READ,$app)) { $dmap = ExecMethod(sprintf('',$app,$class,'list_methods'),'xmlrpc'); } else { $r = CreateObject('phpgwapi.xmlrpcresp', '', $GLOBALS['xmlrpcerr']['no_access'], $GLOBALS['xmlrpcstr']['no_access'] ); return $r; } } } } /* add the functions from preset $dmap OR list_methods() to the server map */ foreach($dmap as $meth => $dat) { $this->add_to_map($meth,$dat['function'],$dat['signature'],$dat['docstring']); } /* _debug_array($this->dmap);exit; */ /* Now make the call */ if(isset($dmap[$methName]['function'])) { // dispatch if exists if(isset($dmap[$methName]['signature'])) { $sr = $this->verifySignature($m, $dmap[$methName]['signature'] ); } if((!isset($dmap[$methName]['signature'])) || $sr[0]) { // if no signature or correct signature $r = xmlrpc_server_call_method($this->server,$data,$params); } else { $r = CreateObject('phpgwapi.xmlrpcresp', '', $GLOBALS['xmlrpcerr']['incorrect_params'], $GLOBALS['xmlrpcstr']['incorrect_params'] . ': ' . $sr[1] ); } } else { // else prepare error response if(!$this->authed) { // $r = False; // send 401 header to force authorization $r = CreateObject('phpgwapi.xmlrpcresp', CreateObject('phpgwapi.xmlrpcval', 'UNAUTHORIZED', 'string' ) ); } else { $r = CreateObject('phpgwapi.xmlrpcresp', '', $GLOBALS['xmlrpcerr']['unknown_method'], $GLOBALS['xmlrpcstr']['unknown_method'] . ': ' . $methName ); } } xmlrpc_server_destroy($xmlrpc_server); return $r; } function echoInput() { global $HTTP_RAW_POST_DATA; // a debugging routine: just echos back the input // packet as a string value /* TODO */ // $r = CreateObject('phpgwapi.xmlrpcresp',CreateObject('phpgwapi.xmlrpcval',"'Aha said I: '" . $HTTP_RAW_POST_DATA,'string')); return $HTTP_RAW_POST_DATA; } function xmlrpc_custom_error($error_number, $error_string, $filename, $line, $vars) { if(error_reporting() & $error_number) { $error_string .= sprintf("\nFilename: %s\nLine: %s",$filename,$line); xmlrpc_error(1005,$error_string); } } /* function xmlrpc_error($error_number, $error_string) { $values = array( 'faultString' => $error_string, 'faultCode' => $error_number ); echo xmlrpc_encode_request(NULL,$values); xmlrpc_server_destroy($GLOBALS['xmlrpc_server']); exit; } */ function xmlrpc_error($error_number, $error_string) { $r = CreateObject('phpgwapi.xmlrpcresp', '', $error_number, $error_string . ': ' . $this->last_method ); $this->service($r); exit; } }