mirror of
https://github.com/EGroupware/egroupware.git
synced 2025-02-06 13:30:35 +01:00
moved access checks into the class with a default implementation, so commands can override it, to be eg. anonymous or under other restrictions available
This commit is contained in:
parent
40a68b6cfd
commit
e195efadeb
@ -19,18 +19,21 @@ abstract class admin_cmd
|
|||||||
const scheduled = 1;
|
const scheduled = 1;
|
||||||
const successful = 2;
|
const successful = 2;
|
||||||
const failed = 3;
|
const failed = 3;
|
||||||
|
const pending = 4;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The status of the command, one of either scheduled, successful, failed or deleted
|
* The status of the command, one of either scheduled, successful, failed or deleted
|
||||||
*
|
*
|
||||||
* @var int
|
* @var int
|
||||||
*/
|
*/
|
||||||
private $status;
|
protected $status;
|
||||||
|
|
||||||
static $stati = array(
|
static $stati = array(
|
||||||
admin_cmd::scheduled => 'scheduled',
|
admin_cmd::scheduled => 'scheduled',
|
||||||
admin_cmd::successful => 'successful',
|
admin_cmd::successful => 'successful',
|
||||||
admin_cmd::failed => 'failed',
|
admin_cmd::failed => 'failed',
|
||||||
admin_cmd::deleted => 'deleted',
|
admin_cmd::deleted => 'deleted',
|
||||||
|
admin_cmd::pending => 'pending',
|
||||||
);
|
);
|
||||||
|
|
||||||
protected $created;
|
protected $created;
|
||||||
@ -40,8 +43,8 @@ abstract class admin_cmd
|
|||||||
private $modified;
|
private $modified;
|
||||||
private $modifier;
|
private $modifier;
|
||||||
private $modifier_email;
|
private $modifier_email;
|
||||||
private $error;
|
protected $error;
|
||||||
private $errno;
|
protected $errno;
|
||||||
public $requested;
|
public $requested;
|
||||||
public $requested_email;
|
public $requested_email;
|
||||||
public $comment;
|
public $comment;
|
||||||
@ -167,7 +170,7 @@ abstract class admin_cmd
|
|||||||
{
|
{
|
||||||
$ret = $this->remote_exec();
|
$ret = $this->remote_exec();
|
||||||
}
|
}
|
||||||
$this->status = admin_cmd::successful;
|
if (is_null($this->status)) $this->status = admin_cmd::successful;
|
||||||
}
|
}
|
||||||
catch (Exception $e) {
|
catch (Exception $e) {
|
||||||
$this->error = $e->getMessage();
|
$this->error = $e->getMessage();
|
||||||
@ -229,7 +232,10 @@ abstract class admin_cmd
|
|||||||
);
|
);
|
||||||
$url = $remote['remote_url'].'/admin/remote.php?domain='.urlencode($remote['remote_domain']).'&secret='.urlencode($secret);
|
$url = $remote['remote_url'].'/admin/remote.php?domain='.urlencode($remote['remote_domain']).'&secret='.urlencode($secret);
|
||||||
//echo "sending command to $url\n"; _debug_array($opts);
|
//echo "sending command to $url\n"; _debug_array($opts);
|
||||||
$message = file_get_contents($url, false, stream_context_create($opts));
|
if (!($message = @file_get_contents($url, false, stream_context_create($opts))))
|
||||||
|
{
|
||||||
|
throw new egw_exception(lang('Could not remote execute the command').': '.$http_response_header[0]);
|
||||||
|
}
|
||||||
//echo "got: $message\n";
|
//echo "got: $message\n";
|
||||||
|
|
||||||
if (($value = unserialize($message)) !== false && $message !== serialize(false))
|
if (($value = unserialize($message)) !== false && $message !== serialize(false))
|
||||||
@ -283,7 +289,7 @@ abstract class admin_cmd
|
|||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (is_null($this->id))
|
if (!$this->id)
|
||||||
{
|
{
|
||||||
$this->id = admin_cmd::$sql->data['id'];
|
$this->id = admin_cmd::$sql->data['id'];
|
||||||
// if the cmd has no uid yet, we create one from our id and the install-id of this eGW instance
|
// if the cmd has no uid yet, we create one from our id and the install-id of this eGW instance
|
||||||
@ -429,6 +435,12 @@ abstract class admin_cmd
|
|||||||
{
|
{
|
||||||
return $this->$property; // making all (non static) class vars readonly available
|
return $this->$property; // making all (non static) class vars readonly available
|
||||||
}
|
}
|
||||||
|
switch($property)
|
||||||
|
{
|
||||||
|
case 'accounts':
|
||||||
|
self::_instanciate_accounts();
|
||||||
|
return self::$accounts;
|
||||||
|
}
|
||||||
return $this->data[$property];
|
return $this->data[$property];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -658,7 +670,7 @@ abstract class admin_cmd
|
|||||||
* @todo accounts class instanciation for setup
|
* @todo accounts class instanciation for setup
|
||||||
* @throws egw_exception_assertion_failed(lang('%1 class not instanciated','accounts'),999);
|
* @throws egw_exception_assertion_failed(lang('%1 class not instanciated','accounts'),999);
|
||||||
*/
|
*/
|
||||||
protected function _instanciate_accounts()
|
static function _instanciate_accounts()
|
||||||
{
|
{
|
||||||
if (!is_object(admin_cmd::$accounts))
|
if (!is_object(admin_cmd::$accounts))
|
||||||
{
|
{
|
||||||
@ -857,7 +869,7 @@ abstract class admin_cmd
|
|||||||
{
|
{
|
||||||
$data['remote_hash'] = self::remote_hash($data['install_id'],$data['config_passwd']);
|
$data['remote_hash'] = self::remote_hash($data['install_id'],$data['config_passwd']);
|
||||||
}
|
}
|
||||||
elseif ($data['install_id'] || $data['config_passwd'] || !$data['remote_hash'])
|
elseif (!$data['remote_hash'] && !($data['install_id'] && $data['config_passwd']))
|
||||||
{
|
{
|
||||||
throw new egw_exception_wrong_userinput(lang('Either Install ID AND config password needed OR the remote hash!'));
|
throw new egw_exception_wrong_userinput(lang('Either Install ID AND config password needed OR the remote hash!'));
|
||||||
}
|
}
|
||||||
@ -914,4 +926,41 @@ abstract class admin_cmd
|
|||||||
{
|
{
|
||||||
return preg_match('/^[0-9a-f]{32}$/',$str);
|
return preg_match('/^[0-9a-f]{32}$/',$str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the current command has the right crediential to be excuted remotely
|
||||||
|
*
|
||||||
|
* Command can reimplement that method, to allow eg. anonymous execution.
|
||||||
|
*
|
||||||
|
* This default implementation use a secret to authenticate with the installation,
|
||||||
|
* 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)
|
||||||
|
*
|
||||||
|
* @param string $secret hash used to authenticate the command (
|
||||||
|
* @param string $config_passwd of the current domain
|
||||||
|
* @throws egw_exception_no_permission
|
||||||
|
*/
|
||||||
|
function check_remote_access($secret,$config_passwd)
|
||||||
|
{
|
||||||
|
// as a security measure remote administration need to be enabled under Admin > Site configuration
|
||||||
|
list(,$remote_admin_install_id) = explode('-',$this->uid);
|
||||||
|
$allowed_remote_admin_ids = $GLOBALS['egw_info']['server']['allow_remote_admin'] ? explode(',',$GLOBALS['egw_info']['server']['allow_remote_admin']) : array();
|
||||||
|
|
||||||
|
// 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 (is_null($config_passwd) || is_numeric($this->uid) || !in_array($remote_admin_install_id,$allowed_remote_admin_ids) ||
|
||||||
|
$secret != ($md5=md5($this->uid.$this->remote_hash($GLOBALS['egw_info']['server']['install_id'],$config_passwd))))
|
||||||
|
{
|
||||||
|
//die("secret='$secret' != '$md5', is_null($config_passwd)=".is_null($config_passwd).", uid=$this->uid, remote_install_id=$remote_admin_install_id, allowed: ".implode(', ',$allowed_remote_admin_ids));
|
||||||
|
$msg = lang('Permission denied!');
|
||||||
|
if (!in_array($remote_admin_install_id,$allowed_remote_admin_ids))
|
||||||
|
{
|
||||||
|
$msg .= "\n".lang('Remote administration need to be enabled in the remote instance under Admin > Site configuration!');
|
||||||
|
}
|
||||||
|
throw new egw_exception_no_permission($msg,0);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
admin_cmd::_instanciate_accounts();
|
||||||
|
@ -22,6 +22,20 @@ $GLOBALS['egw_info'] = array(
|
|||||||
|
|
||||||
include('../header.inc.php');
|
include('../header.inc.php');
|
||||||
|
|
||||||
|
// install an own exception handler to forward exceptions back to the remote side
|
||||||
|
function remote_exception_handler(Exception $e)
|
||||||
|
{
|
||||||
|
$msg = $e->getMessage();
|
||||||
|
if (is_object($GLOBALS['egw']->translation))
|
||||||
|
{
|
||||||
|
$msg = $GLOBALS['egw']->translation->convert($msg,$GLOBALS['egw']->translation->charset(),'utf-8');
|
||||||
|
}
|
||||||
|
header('HTTP/1.1 200 '.$msg);
|
||||||
|
echo $e->getCode().' '.$msg;
|
||||||
|
$GLOBALS['egw']->common->egw_exit();
|
||||||
|
}
|
||||||
|
set_exception_handler('remote_exception_handler');
|
||||||
|
|
||||||
$GLOBALS['egw']->applications->read_installed_apps(); // set $GLOBALS['egw_info']['apps'] (not set for login)
|
$GLOBALS['egw']->applications->read_installed_apps(); // set $GLOBALS['egw_info']['apps'] (not set for login)
|
||||||
|
|
||||||
$instance = isset($_GET['domain']) ? $_GET['domain'] : $_REQUEST['domain']; // use GET before the rest
|
$instance = isset($_GET['domain']) ? $_GET['domain'] : $_REQUEST['domain']; // use GET before the rest
|
||||||
@ -29,27 +43,8 @@ if (!isset($GLOBALS['egw_domain'][$instance]))
|
|||||||
{
|
{
|
||||||
$instance = $GLOBALS['egw_info']['server']['default_domain'];
|
$instance = $GLOBALS['egw_info']['server']['default_domain'];
|
||||||
}
|
}
|
||||||
$domain_data = $GLOBALS['egw_domain'][$instance];
|
$config_passwd = $GLOBALS['egw_domain'][$instance]['config_passwd'];
|
||||||
//echo $instance; _debug_array($domain_data);
|
unset($GLOBALS['egw_domain']);
|
||||||
|
|
||||||
// as a security measure remote administration need to be enabled under Admin > Site configuration
|
|
||||||
list(,$remote_admin_install_id) = explode('-',$_REQUEST['uid']);
|
|
||||||
$allowed_remote_admin_ids = $GLOBALS['egw_info']['server']['allow_remote_admin'] ? explode(',',$GLOBALS['egw_info']['server']['allow_remote_admin']) : array();
|
|
||||||
// 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']) || !in_array($remote_admin_install_id,$allowed_remote_admin_ids) ||
|
|
||||||
$_REQUEST['secret'] != ($md5=md5($_REQUEST['uid'].admin_cmd::remote_hash($GLOBALS['egw_info']['server']['install_id'],$domain_data['config_passwd']))))
|
|
||||||
{
|
|
||||||
header("HTTP/1.1 200 Unauthorized");
|
|
||||||
//die("0 secret != '$md5'");
|
|
||||||
echo lang('0 Permission denied!');
|
|
||||||
if (!in_array($remote_admin_install_id,$allowed_remote_admin_ids))
|
|
||||||
{
|
|
||||||
echo "\n".lang('Remote administration need to be enabled in the remote instance under Admin > Site configuration!');
|
|
||||||
}
|
|
||||||
$GLOBALS['egw']->common->egw_exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
require_once(EGW_INCLUDE_ROOT.'/admin/inc/class.admin_cmd.inc.php');
|
require_once(EGW_INCLUDE_ROOT.'/admin/inc/class.admin_cmd.inc.php');
|
||||||
|
|
||||||
@ -58,7 +53,15 @@ require_once(EGW_INCLUDE_ROOT.'/admin/inc/class.admin_cmd.inc.php');
|
|||||||
$cmd = admin_cmd::read($_REQUEST['uid']);
|
$cmd = admin_cmd::read($_REQUEST['uid']);
|
||||||
if (is_object($cmd))
|
if (is_object($cmd))
|
||||||
{
|
{
|
||||||
exit_with_status($cmd);
|
$cmd->check_remote_access($_REQUEST['secret'],$config_passwd);
|
||||||
|
|
||||||
|
$success_msg = 'Successful';
|
||||||
|
// if the comand object has a rerun method, call it
|
||||||
|
if (method_exists($cmd,'rerun'))
|
||||||
|
{
|
||||||
|
$success_msg = $cmd->rerun();
|
||||||
|
}
|
||||||
|
exit_with_status($cmd,$success_msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if requests contains a reasonable looking admin command to be queued
|
// check if requests contains a reasonable looking admin command to be queued
|
||||||
@ -67,7 +70,7 @@ if (!$_REQUEST['uid'] || // no uid
|
|||||||
!$_REQUEST['creator_email']) // no creator email
|
!$_REQUEST['creator_email']) // no creator email
|
||||||
{
|
{
|
||||||
header("HTTP/1.1 200 Bad format!");
|
header("HTTP/1.1 200 Bad format!");
|
||||||
echo lang('0 Bad format!');
|
echo '0 Bad format!';
|
||||||
$GLOBALS['egw']->common->egw_exit();
|
$GLOBALS['egw']->common->egw_exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,22 +84,18 @@ if (isset($data['modifier'])) $data['modifier'] = 0;
|
|||||||
if (isset($data['requested'])) $data['requested'] = 0;
|
if (isset($data['requested'])) $data['requested'] = 0;
|
||||||
|
|
||||||
// instanciate comand and run it
|
// instanciate comand and run it
|
||||||
try {
|
$cmd = admin_cmd::instanciate($data);
|
||||||
$cmd = admin_cmd::instanciate($data);
|
|
||||||
//_debug_array($cmd); exit;
|
|
||||||
$success_msg = $cmd->run();
|
|
||||||
|
|
||||||
$GLOBALS['egw']->translation->convert($success_msg,$GLOBALS['egw']->translation->charset(),'utf-8');
|
|
||||||
|
|
||||||
if (!is_string($success_msg))
|
$cmd->check_remote_access($_REQUEST['secret'],$config_passwd);
|
||||||
{
|
|
||||||
$success_msg = serialize($success_msg);
|
//_debug_array($cmd); exit;
|
||||||
}
|
$success_msg = $cmd->run();
|
||||||
}
|
|
||||||
catch (Exception $e) {
|
$GLOBALS['egw']->translation->convert($success_msg,$GLOBALS['egw']->translation->charset(),'utf-8');
|
||||||
header('HTTP/1.1 200 '.$e->getMessage());
|
|
||||||
echo $e->getCode().' '.$e->getMessage();
|
if (!is_string($success_msg))
|
||||||
$GLOBALS['egw']->common->egw_exit();
|
{
|
||||||
|
$success_msg = serialize($success_msg);
|
||||||
}
|
}
|
||||||
exit_with_status($cmd,$success_msg);
|
exit_with_status($cmd,$success_msg);
|
||||||
|
|
||||||
@ -112,6 +111,7 @@ function exit_with_status($cmd,$success_msg='Successful')
|
|||||||
default: // everything else is returned as 200 HTTP status
|
default: // everything else is returned as 200 HTTP status
|
||||||
$success_msg = $cmd->stati[$cmd->status];
|
$success_msg = $cmd->stati[$cmd->status];
|
||||||
// fall through
|
// fall through
|
||||||
|
case admin_cmd::pending:
|
||||||
case admin_cmd::successful:
|
case admin_cmd::successful:
|
||||||
header('HTTP/1.1 200 '.$cmd->stati[$cmd->status]);
|
header('HTTP/1.1 200 '.$cmd->stati[$cmd->status]);
|
||||||
header('Content-type: text/plain; charset=utf-8');
|
header('Content-type: text/plain; charset=utf-8');
|
||||||
|
Loading…
Reference in New Issue
Block a user