diff --git a/admin/admin-cli.php b/admin/admin-cli.php index 43e17ca98e..f4f9ef6c5d 100755 --- a/admin/admin-cli.php +++ b/admin/admin-cli.php @@ -114,6 +114,10 @@ function run_command($cmd) $cmd->comment = array_shift($arguments); break; + case '--remote': // run the command on a remote install + $cmd->remote_id = admin_cmd::parse_remote(array_shift($arguments)); + break; + default: //fail(99,lang('Unknown option %1',$extra); echo lang('Unknown option %1',$extra)."\n\n"; @@ -121,6 +125,7 @@ function run_command($cmd) break; } } + //_debug_array($cmd); return $cmd->run($time); } @@ -162,7 +167,7 @@ function user_pass_from_argv(&$account) function usage($action=null,$ret=0) { $cmd = basename($_SERVER['argv'][0]); - echo "Usage: $cmd --command admin-account[@domain],admin-password,options,... [--schedule {YYYY-mm-dd|+1 week|+5 days}] [--requested 'Name '] [--comment 'comment ...']\n\n"; + echo "Usage: $cmd --command admin-account[@domain],admin-password,options,... [--schedule {YYYY-mm-dd|+1 week|+5 days}] [--requested 'Name '] [--comment 'comment ...'] [--remote {id|name}]\n\n"; echo "--edit-user admin-account[@domain],admin-password,account[=new-account-name],first-name,last-name,password,email,expires{never(default)|YYYY-MM-DD|already},can-change-pw{yes(default)|no},anon-user{yes|no(default)},primary-group{Default(default)|...}[,groups,...]\n"; echo " Edit or add a user to eGroupWare. If you specify groups, they *replace* the exiting memberships!\n"; diff --git a/admin/inc/class.admin_cmd.inc.php b/admin/inc/class.admin_cmd.inc.php index db57804893..5dd693eac8 100644 --- a/admin/inc/class.admin_cmd.inc.php +++ b/admin/inc/class.admin_cmd.inc.php @@ -50,6 +50,8 @@ abstract class admin_cmd private $id; private $uid; private $type = __CLASS__; + public $remote_id; + /** * Stores the data of the derived classes * @@ -78,6 +80,13 @@ abstract class admin_cmd */ static private $sql; + /** + * Instance of so_sql for egw_admin_remote + * + * @var so_sql + */ + static private $remote; + /** * Executes the command * @@ -136,7 +145,14 @@ abstract class admin_cmd else { try { - $ret = $this->exec(); + if (!$this->remote_id) + { + $ret = $this->exec(); + } + else + { + $ret = $this->remote_exec(); + } $this->status = admin_cmd::successful; } catch (Exception $e) { @@ -152,6 +168,61 @@ abstract class admin_cmd return $ret; } + /** + * Runs a command on a remote install + * + * This is a very basic remote procedure call to an other egw instance. + * The payload / command data is send as POST request to the remote installs admin/remote.php script. + * The remote domain (eGW instance) and the secret authenticating the request are send as GET parameters. + * + * To authenticate with the installation we use a secret, which is a md5 hash build from the uid + * of the command (to not allow to send new commands with an earsdroped secret) and the md5 hash + * of the md5 hash of the config password and the install_id (egw_admin_remote.remote_hash) + * + * @return string sussess message + * @throws Exception(lang('Invalid remote id or name "%1"!',$id_or_name),997) or other Exceptions reported from remote + */ + private function remote_exec() + { + admin_cmd::_instanciate_remote(); + + if (!($remote = admin_cmd::$remote->read($this->remote_id))) + { + throw new Exception(lang('Invalid remote id or name "%1"!',$id_or_name),997); + } + if (!$this->uid) + { + $this->save(); // to get the uid + } + $secret = md5($this->uid.$remote['remote_hash']); + + $postdata = $GLOBALS['egw']->translation->convert($this->as_array(),$GLOBALS['egw']->translation->charset(),'utf-8'); + // dont send the id's which have no meaning on the remote install + foreach(array('id','creator','modifier','requested','remote_id') as $name) + { + unset($postdata[$name]); + } + $opts = array('http' => + array( + 'method' => 'POST', + 'header' => 'Content-type: application/x-www-form-urlencoded', + 'content' => http_build_query($postdata), + ) + ); + $url = $remote['remote_url'].'/admin/remote.php?domain='.urlencode($remote['remote_domain']).'&secret='.urlencode($secret); + //echo "sending command to $url\n"; _debug_array($opts); + $message = file_get_contents($url, false, stream_context_create($opts)); + //echo "got: $message\n"; + + $message = $GLOBALS['egw']->translation->convert($message,'utf-8'); + + if (preg_match('/^([0-9]+) (.*)$/',$message,$matches)) + { + throw new Exception($matches[2],(int)$matches[1]); + } + return $message; + } + /** * Delete / canncels a scheduled command * @@ -301,20 +372,35 @@ abstract class admin_cmd } /** - * Instanciate our static so_sql object + * Instanciate our static so_sql object for egw_admin_queue * * @static */ private static function _instanciate_sql() { - include_once(EGW_INCLUDE_ROOT.'/etemplate/inc/class.so_sql.inc.php'); - if (is_null(admin_cmd::$sql)) { + include_once(EGW_INCLUDE_ROOT.'/etemplate/inc/class.so_sql.inc.php'); + admin_cmd::$sql = new so_sql('admin','egw_admin_queue',null,'cmd_'); } } + /** + * Instanciate our static so_sql object for egw_admin_remote + * + * @static + */ + private static function _instanciate_remote() + { + if (is_null(admin_cmd::$remote)) + { + include_once(EGW_INCLUDE_ROOT.'/etemplate/inc/class.so_sql.inc.php'); + + admin_cmd::$remote = new so_sql('admin','egw_admin_remote'); + } + } + /** * magic method to read a property, all non admin-cmd properties are stored in the data array * @@ -437,6 +523,7 @@ abstract class admin_cmd * * @param string $date * @return int timestamp + * @throws Exception(lang('Invalid formated date "%1"!',$datein),998); */ static function parse_date($date) { @@ -453,6 +540,27 @@ abstract class admin_cmd } return (int)$date; } + + /** + * Parse a remote id or name and return the remote_id + * + * @param string $id_or_name + * @return int remote_id + * @throws Exception(lang('Invalid remote id or name "%1"!',$id_or_name),997); + */ + static function parse_remote($id_or_name) + { + admin_cmd::_instanciate_remote(); + + if (!($remotes = admin_cmd::$remote->search(array( + 'remote_id' => $id_or_name, + 'remote_name' => $id_or_name, + ),true,'','','',false,'OR')) || count($remotes) != 1) + { + throw new Exception(lang('Invalid remote id or name "%1"!',$id_or_name),997); + } + return $remotes[0]['remote_id']; + } /** * Instanciated accounts class diff --git a/admin/remote.php b/admin/remote.php index 9132519096..4ed65f2c8b 100644 --- a/admin/remote.php +++ b/admin/remote.php @@ -27,13 +27,17 @@ if (!isset($GLOBALS['egw_domain'][$instance])) $instance = $GLOBALS['egw_info']['server']['default_domain']; } $domain_data = $GLOBALS['egw_domain'][$instance]; +//echo $instance; _debug_array($domain_data); +// to authenticate with the installation we use a secret, which is a md5 hash build from the uid +// of the command (to not allow to send new commands with an earsdroped secret) and the md5 hash +// of the md5 hash of the config password and the install_id (egw_admin_remote.remote_hash) if (!$domain_data || is_numeric($_REQUEST['uid']) || - $_REQUEST['secret'] != ($md5=md5($_REQUEST['uid'].$GLOBALS['egw_info']['server']['install_id'].$domain_data['config_password']))) + $_REQUEST['secret'] != ($md5=md5($_REQUEST['uid'].md5($domain_data['config_passwd'].$GLOBALS['egw_info']['server']['install_id'])))) { header("HTTP/1.1 401 Unauthorized"); - //die("secret != '$md5'"); - echo lang('Permission denied!'); + //die("0 secret != '$md5'"); + echo lang('0 Permission denied!'); $GLOBALS['egw']->common->egw_exit(); } @@ -53,14 +57,15 @@ if (!$_REQUEST['uid'] || // no uid !$_REQUEST['creator_email']) // no creator email { header("HTTP/1.1 400 Bad format!"); - echo lang('Bad format!'); + echo lang('0 Bad format!'); $GLOBALS['egw']->common->egw_exit(); } // create command from request data $data = isset($_POST['uid']) ? $_POST : $_GET; unset($data['secret']); -unset($data['id']); // we are remote +unset($data['id']); // we are remote +unset($data['remote_id']); $data['creator'] = 0; // remote if (isset($data['modifier'])) $data['modifier'] = 0; if (isset($data['requested'])) $data['requested'] = 0; @@ -69,7 +74,7 @@ if (isset($data['requested'])) $data['requested'] = 0; try { $cmd = admin_cmd::instanciate($data); //_debug_array($cmd); exit; - $success_msg = $cmd->run($data['sheduled']); + $success_msg = $cmd->run(); } catch (Exception $e) { header('HTTP/1.1 400 '.$e->getMessage()); diff --git a/admin/setup/setup.inc.php b/admin/setup/setup.inc.php index 6980076b4f..f11aab0c5e 100755 --- a/admin/setup/setup.inc.php +++ b/admin/setup/setup.inc.php @@ -10,9 +10,9 @@ */ $setup_info['admin']['name'] = 'admin'; -$setup_info['admin']['version'] = '1.5.001'; +$setup_info['admin']['version'] = '1.5.003'; $setup_info['admin']['app_order'] = 1; -$setup_info['admin']['tables'] = array('egw_admin_queue'); +$setup_info['admin']['tables'] = array('egw_admin_queue','egw_admin_remote'); $setup_info['admin']['enable'] = 1; $setup_info['admin']['author'][] = array( @@ -53,3 +53,4 @@ $setup_info['admin']['depends'][] = array( 'appname' => 'etemplate', 'versions' => Array('1.4','1.5') ); + diff --git a/admin/setup/tables_current.inc.php b/admin/setup/tables_current.inc.php index f060cb924a..aea43483e8 100644 --- a/admin/setup/tables_current.inc.php +++ b/admin/setup/tables_current.inc.php @@ -12,30 +12,44 @@ * @version $Id$ */ -$phpgw_baseline = array( - 'egw_admin_queue' => array( - 'fd' => array( - 'cmd_id' => array('type' => 'auto'), - 'cmd_uid' => array('type' => 'varchar','precision' => '255','nullable' => False), - 'cmd_creator' => array('type' => 'int','precision' => '4','nullable' => False), - 'cmd_creator_email' => array('type' => 'varchar','precision' => '128','nullable' => False), - 'cmd_created' => array('type' => 'int','precision' => '8','nullable' => False), - 'cmd_type' => array('type' => 'varchar','precision' => '32','nullable' => False,'default' => 'admin_cmd'), - 'cmd_status' => array('type' => 'int','precision' => '1'), - 'cmd_scheduled' => array('type' => 'int','precision' => '8'), - 'cmd_modified' => array('type' => 'int','precision' => '8'), - 'cmd_modifier' => array('type' => 'int','precision' => '4'), - 'cmd_modifier_email' => array('type' => 'varchar','precision' => '128'), - 'cmd_error' => array('type' => 'varchar','precision' => '255'), - 'cmd_errno' => array('type' => 'int','precision' => '4'), - 'cmd_requested' => array('type' => 'int','precision' => '4'), - 'cmd_requested_email' => array('type' => 'varchar','precision' => '128'), - 'cmd_comment' => array('type' => 'varchar','precision' => '255'), - 'cmd_data' => array('type' => 'blob') + $phpgw_baseline = array( + 'egw_admin_queue' => array( + 'fd' => array( + 'cmd_id' => array('type' => 'auto'), + 'cmd_uid' => array('type' => 'varchar','precision' => '255','nullable' => False), + 'cmd_creator' => array('type' => 'int','precision' => '4','nullable' => False), + 'cmd_creator_email' => array('type' => 'varchar','precision' => '128','nullable' => False), + 'cmd_created' => array('type' => 'int','precision' => '8','nullable' => False), + 'cmd_type' => array('type' => 'varchar','precision' => '32','nullable' => False,'default' => 'admin_cmd'), + 'cmd_status' => array('type' => 'int','precision' => '1'), + 'cmd_scheduled' => array('type' => 'int','precision' => '8'), + 'cmd_modified' => array('type' => 'int','precision' => '8'), + 'cmd_modifier' => array('type' => 'int','precision' => '4'), + 'cmd_modifier_email' => array('type' => 'varchar','precision' => '128'), + 'cmd_error' => array('type' => 'varchar','precision' => '255'), + 'cmd_errno' => array('type' => 'int','precision' => '4'), + 'cmd_requested' => array('type' => 'int','precision' => '4'), + 'cmd_requested_email' => array('type' => 'varchar','precision' => '128'), + 'cmd_comment' => array('type' => 'varchar','precision' => '255'), + 'cmd_data' => array('type' => 'blob'), + 'remote_id' => array('type' => 'int','precision' => '4') + ), + 'pk' => array('cmd_id'), + 'fk' => array(), + 'ix' => array('cmd_status','cmd_scheduled'), + 'uc' => array('cmd_uid') ), - 'pk' => array('cmd_id'), - 'fk' => array(), - 'ix' => array('cmd_status','cmd_scheduled'), - 'uc' => array('cmd_uid') - ) -); + 'egw_admin_remote' => array( + 'fd' => array( + 'remote_id' => array('type' => 'auto'), + 'remote_name' => array('type' => 'varchar','precision' => '64','nullable' => False), + 'remote_hash' => array('type' => 'varchar','precision' => '32','nullable' => False), + 'remote_url' => array('type' => 'varchar','precision' => '128','nullable' => False), + 'remote_domain' => array('type' => 'varchar','precision' => '64','nullable' => False) + ), + 'pk' => array('remote_id'), + 'fk' => array(), + 'ix' => array(), + 'uc' => array('remote_name') + ) + ); diff --git a/admin/setup/tables_update.inc.php b/admin/setup/tables_update.inc.php index 4e8f865f8d..e0b4587ba0 100644 --- a/admin/setup/tables_update.inc.php +++ b/admin/setup/tables_update.inc.php @@ -12,6 +12,11 @@ * @version $Id$ */ +function admin_upgrade1_2() +{ + return $GLOBALS['setup_info']['admin']['currentver'] = '1.4'; +} + function admin_upgrade1_4() { $GLOBALS['egw_setup']->oProc->CreateTable('egw_admin_queue',array( @@ -41,3 +46,36 @@ function admin_upgrade1_4() )); return $GLOBALS['setup_info']['admin']['currentver'] = '1.5.001'; } + + $test[] = '1.5.001'; + function admin_upgrade1_5_001() + { + $GLOBALS['egw_setup']->oProc->CreateTable('egw_admin_remote',array( + 'fd' => array( + 'remote_id' => array('type' => 'auto'), + 'remote_name' => array('type' => 'varchar','precision' => '64','nullable' => False), + 'remote_hash' => array('type' => 'varchar','precision' => '32','nullable' => False), + 'remote_url' => array('type' => 'varchar','precision' => '128','nullable' => False), + 'remote_domain' => array('type' => 'varchar','precision' => '64','nullable' => False) + ), + 'pk' => array('remote_id'), + 'fk' => array(), + 'ix' => array(), + 'uc' => array('remote_name') + )); + + return $GLOBALS['setup_info']['admin']['currentver'] = '1.5.002'; + } + + + $test[] = '1.5.002'; + function admin_upgrade1_5_002() + { + $GLOBALS['egw_setup']->oProc->AddColumn('egw_admin_queue','remote_id',array( + 'type' => 'int', + 'precision' => '4' + )); + + return $GLOBALS['setup_info']['admin']['currentver'] = '1.5.003'; + } +?>