From 4f77162f649e830b1737a77447f2ff794d836a88 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Wed, 5 Dec 2007 02:27:49 +0000 Subject: [PATCH] first version of a setup command that can run via admins remote command execution --- admin/admin-cli.php | 23 +++++- admin/inc/class.admin_cmd.inc.php | 33 ++++++--- admin/inc/class.admin_cmds.inc.php | 7 +- admin/remote.php | 9 ++- setup/inc/class.setup_cmd.inc.php | 68 +++++++++++++++++ setup/inc/class.setup_cmd_showheader.inc.php | 77 ++++++++++++++++++++ 6 files changed, 198 insertions(+), 19 deletions(-) create mode 100644 setup/inc/class.setup_cmd.inc.php create mode 100644 setup/inc/class.setup_cmd_showheader.inc.php diff --git a/admin/admin-cli.php b/admin/admin-cli.php index ec0c0da611..8f964ac246 100755 --- a/admin/admin-cli.php +++ b/admin/admin-cli.php @@ -78,6 +78,9 @@ switch($action) case '--check-acl'; return do_check_acl(); + case '--show-header'; + return run_command(new setup_cmd_showheader()); + case '--exit-codes': return list_exit_codes(); @@ -123,6 +126,14 @@ function run_command(admin_cmd $cmd) case '--skip-checks': //do not yet run the checks for scheduled local commands $skip_checks = true; break; + + case '--header-access': + if ($cmd instanceof setup_cmd) + { + list($user,$pw) = explode(',',array_shift($arguments),2); + $cmd->set_header_secret($user,$pw); + } + break; default: //fail(99,lang('Unknown option %1',$extra); @@ -138,7 +149,15 @@ function run_command(admin_cmd $cmd) { fail($cmd->errno,$cmd->error); } - echo $msg."\n\n"; + if (($value = unserialize($msg)) !== false && $msg !== serialize(false)) + { + print_r($value); + echo "\n"; + } + else + { + echo $msg."\n\n"; + } exit(0); } @@ -441,4 +460,4 @@ function do_subscribe_other($account_lid,$pw=null) //$icServer->subscribeMailbox($mailbox); //exit; } -} \ No newline at end of file +} diff --git a/admin/inc/class.admin_cmd.inc.php b/admin/inc/class.admin_cmd.inc.php index 293f1bd44a..ac7f74581b 100644 --- a/admin/inc/class.admin_cmd.inc.php +++ b/admin/inc/class.admin_cmd.inc.php @@ -15,8 +15,6 @@ */ abstract class admin_cmd { - const edit_user = 16; - const deleted = 0; const scheduled = 1; const successful = 2; @@ -29,7 +27,7 @@ abstract class admin_cmd private $status; static $stati = array( - admin_cmd::scheduled => 'scheduled', + admin_cmd::scheduled => 'scheduled', admin_cmd::successful => 'successful', admin_cmd::failed => 'failed', admin_cmd::deleted => 'deleted', @@ -48,7 +46,7 @@ abstract class admin_cmd public $requested_email; public $comment; private $id; - private $uid; + protected $uid; private $type = __CLASS__; public $remote_id; @@ -394,8 +392,6 @@ abstract class admin_cmd { 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_'); } } @@ -409,8 +405,6 @@ abstract class admin_cmd { 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'); } } @@ -815,7 +809,7 @@ abstract class admin_cmd * Save / adds a remote instance * * @param array $data - * @return array/boolean data including remote_id or false on failure + * @return int remote_id */ static function save_remote(array $data) { @@ -823,17 +817,21 @@ abstract class admin_cmd if ($data['install_id'] && $data['config_passwd']) // calculate hash { - $pw = preg_match('/^[a-f0-9]{32}$/',$data['config_passwd']) ? $data['config_passwd'] : md5($data['config_passwd']); + $pw = self::is_md5($data['config_passwd']) ? $data['config_passwd'] : md5($data['config_passwd']); $data['remote_hash'] = md5($pw.$data['install_id']); } elseif ($data['install_id'] || $data['config_passwd'] || !$data['remote_hash']) { - return false; // we need either install_id AND config_passwd OR the remote_hash + throw new Exception(lang('Either Install ID AND config password needed OR the remote hash!')); } //_debug_array($data); admin_cmd::$remote->init($data); - return admin_cmd::$remote->save() == 0 ? admin_cmd::$remote->data : false; + if (admin_cmd::$remote->save() != 0) + { + throw new Exception (lang('Error saving to db:').' '.$this->sql->db->Error.' ('.$this->sql->db->Errno.')',$this->sql->db->Errno); + } + return admin_cmd::$remote->data['remote_id']; } /** @@ -850,4 +848,15 @@ abstract class admin_cmd return $account.' ('.$GLOBALS['egw']->common->grab_owner_name($id).')'; } + + /** + * Check if string is a md5 hash (32 chars of 0-9 or a-f) + * + * @param string $str + * @return boolean + */ + static function is_md5($str) + { + return preg_match('/^[0-9a-f]{32}$/',$str); + } } diff --git a/admin/inc/class.admin_cmds.inc.php b/admin/inc/class.admin_cmds.inc.php index 801845c754..4ddb711b2e 100644 --- a/admin/inc/class.admin_cmds.inc.php +++ b/admin/inc/class.admin_cmds.inc.php @@ -157,9 +157,12 @@ class admin_cmds $content['msg'] = lang('You need to enter Install ID AND Password!'); break; } - if (($content['remote'] = admin_cmd::save_remote($content['remote']))) - { + try { + $content['remote']['remote_id'] = admin_cmd::save_remote($content['remote']); $content['msg'] = lang('Remote instance saved'); + } catch (Exception $e) { + $content['msg'] = lang('Error saving').': '.$e->getMessage().' ('.$e->getCode().')'; + break; } if ($button == 'apply') break; // fall through for save diff --git a/admin/remote.php b/admin/remote.php index 91dc2f3471..ac66aac0c6 100644 --- a/admin/remote.php +++ b/admin/remote.php @@ -1,6 +1,6 @@ @@ -10,6 +10,9 @@ * @version $Id$ */ +/** + * @var array + */ $GLOBALS['egw_info'] = array( 'flags' => array( 'currentapp' => 'login', @@ -21,7 +24,7 @@ include('../header.inc.php'); $GLOBALS['egw']->applications->read_installed_apps(); // set $GLOBALS['egw_info']['apps'] (not set for login) -$instance = $_REQUEST['domain']; +$instance = isset($_GET['domain']) ? $_GET['domain'] : $_REQUEST['domain']; // use GET before the rest if (!isset($GLOBALS['egw_domain'][$instance])) { $instance = $GLOBALS['egw_info']['server']['default_domain']; @@ -39,7 +42,7 @@ if (!$domain_data || is_numeric($_REQUEST['uid']) || !in_array($remote_admin_ins $_REQUEST['secret'] != ($md5=md5($_REQUEST['uid'].md5($domain_data['config_passwd'].$GLOBALS['egw_info']['server']['install_id'])))) { header("HTTP/1.1 200 Unauthorized"); - //die("0 secret != '$md5'"); + die("0 secret != '$md5'"); echo lang('0 Permission denied!'); if (!in_array($remote_admin_install_id,$allowed_remote_admin_ids)) { diff --git a/setup/inc/class.setup_cmd.inc.php b/setup/inc/class.setup_cmd.inc.php new file mode 100644 index 0000000000..a2851173ec --- /dev/null +++ b/setup/inc/class.setup_cmd.inc.php @@ -0,0 +1,68 @@ + + * @package setup + * @copyright (c) 2007 by Ralf Becker + * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License + * @version $Id: class.admin_cmd_check_acl.inc.php 24709 2007-11-27 03:20:28Z ralfbecker $ + */ + +/** + * setup command: abstract baseclass for all setup commands, extending admin_cmd + */ +abstract class setup_cmd extends admin_cmd +{ + /** + * Should be called by every command usually requiring header admin rights + * + * @throws Exception(lang('Wrong credentials to access the header.inc.php file!'),2); + */ + protected function _check_header_access() + { + if ($this->header_secret != ($secret = $this->_calc_header_secret($GLOBALS['egw_info']['server']['header_admin_user'], + $GLOBALS['egw_info']['server']['header_admin_password']))) + { + //echo "header_secret='$this->header_secret' != '$secret'=_calc_header_secret({$GLOBALS['egw_info']['server']['header_admin_user']},{$GLOBALS['egw_info']['server']['header_admin_password']})\n"; + throw new Exception (lang('Wrong credentials to access the header.inc.php file!'),2); + } + } + + /** + * Set the user and pw required for any operation on the header file + * + * @param string $user + * @param string $pw password or md5 hash of it + */ + public function set_header_secret($user,$pw) + { + if ($this->uid || parent::save(false)) // we need to save first, to get the uid + { + $this->header_secret = $this->_calc_header_secret($user,$pw); + } + else + { + throw new Exception ('failed to set header_secret!'); + } + } + + /** + * Calculate the header_secret used to access the header from this command + * + * It's an md5 over the uid, header-admin-user and -password. + * + * @param string $header_admin_user + * @param string $header_admin_password + * @return string + */ + private function _calc_header_secret($header_admin_user=null,$header_admin_password=null) + { + if (!self::is_md5($header_admin_password)) $header_admin_password = md5($header_admin_password); + + $secret = md5($this->uid.$header_admin_user.$header_admin_password); + //echo "header_secret='$secret' = md5('$this->uid'.'$header_admin_user'.'$header_admin_password')\n"; + return $secret; + } +} diff --git a/setup/inc/class.setup_cmd_showheader.inc.php b/setup/inc/class.setup_cmd_showheader.inc.php new file mode 100644 index 0000000000..33e882cbb7 --- /dev/null +++ b/setup/inc/class.setup_cmd_showheader.inc.php @@ -0,0 +1,77 @@ + + * @package setup + * @copyright (c) 2007 by Ralf Becker + * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License + * @version $Id: class.admin_cmd_check_acl.inc.php 24709 2007-11-27 03:20:28Z ralfbecker $ + */ + +/** + * setup command: show/return the header.inc.php + * + * Has no constructor, as we have no arguments beside the header admin user and password, + * which get set via setup_cmd::set_header_secret($user,$pw) + */ +class setup_cmd_showheader extends setup_cmd +{ + /** + * Constructor + * + * @param array $data=array() default parm from parent class, no real parameters + */ + function __construct($data=array()) + { + //echo __CLASS__.'::__construct()'; _debug_array($data); + admin_cmd::__construct($data); + } + + /** + * show/return the header.inc.php + * + * @param boolean $check_only=false only run the checks (and throw the exceptions), but not the command itself + * @return string serialized $GLOBALS defined in the header.inc.php + * @throws Exception(lang('Wrong credentials to access the header.inc.php file!'),2); + * @throws Exception('header.inc.php not found!'); + */ + function exec($check_only=false) + { + if ($this->remote_id && $check_only) return true; // cant check for the remote site locally! + + $this->_check_header_access(); + + if ($check_only) return true; + + $egw_info_backup = $GLOBALS['egw_info']; + $GLOBALS['egw_info'] = array ( + 'flags' => array( + 'noapi' => true, + ), + ); + if (!($header = file_get_contents(EGW_SERVER_ROOT.'/header.inc.php'))) + { + throw new Exception('header.inc.php not found!'); + } + eval(str_replace(array(' $GLOBALS['egw_info'], + 'egw_domain' => $GLOBALS['egw_domain'], + 'EGW_SERVER_ROOT' => EGW_SERVER_ROOT, + 'EGW_INCLUDE_ROOT' => EGW_INCLUDE_ROOT, + )); + + $GLOBALS['egw_info'] = $egw_info_backup; + + return $ret; + } +}