You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
zabbix/ui/app/controllers/CControllerActionOperationC...

307 lines
9.2 KiB

1 year ago
<?php declare(strict_types = 0);
/*
** Zabbix
** Copyright (C) 2001-2023 Zabbix SIA
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program 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 General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**/
class CControllerActionOperationCheck extends CController {
protected function init(): void {
$this->setPostContentType(self::POST_CONTENT_TYPE_JSON);
$this->disableCsrfValidation();
}
protected function checkInput(): bool {
$fields = [
'operation' => 'array',
'actionid' => 'db actions.actionid',
'row_index' => 'int32'
];
$ret = $this->validateInput($fields) && $this->validateOperation();
if (!$ret) {
$this->setResponse(
new CControllerResponseData(['main_block' => json_encode([
'error' => [
'messages' => array_column(get_and_clear_messages(), 'message')
]
])])
);
}
return $ret;
}
protected function validateOperation(): bool {
$operation = $this->getInput('operation', []);
$required_fields = ['eventsource', 'recovery', 'operationtype'];
foreach ($required_fields as $field) {
if (!array_key_exists($field, $operation)) {
error(_s('Field "%1$s" is mandatory.', $field));
return false;
}
}
$eventsource = $operation['eventsource'];
$recovery = $operation['recovery'];
$operationtype = preg_replace('[\D]', '', $operation['operationtype']);
$allowed_operations = getAllowedOperations($eventsource);
if (preg_match('/\bscriptid\b/', $operation['operationtype'])) {
$operationtype = OPERATION_TYPE_COMMAND;
}
if (!array_key_exists($recovery, $allowed_operations)
|| !in_array($operationtype, $allowed_operations[$recovery])) {
error(_s('Incorrect action operation type "%1$s" for event source "%2$s".', $operationtype, $eventsource));
return false;
}
$default_msg_validator = new CLimitedSetValidator(['values' => [0, 1]]);
if ($recovery == ACTION_OPERATION) {
if ((array_key_exists('esc_step_from', $operation) || array_key_exists('esc_step_to', $operation))
&& (!array_key_exists('esc_step_from', $operation)
|| !array_key_exists('esc_step_to', $operation))) {
error(_('Parameters "esc_step_from" and "esc_step_to" must be set together.'));
return false;
}
if (array_key_exists('esc_step_from', $operation) && array_key_exists('esc_step_to', $operation)) {
if ($operation['esc_step_from'] < 1 || $operation['esc_step_to'] < 0) {
error(_('Incorrect action operation escalation step values.'));
return false;
}
if ($operation['esc_step_from'] > $operation['esc_step_to'] && $operation['esc_step_to'] != 0) {
error(_('Incorrect action operation escalation step values.'));
return false;
}
}
if (array_key_exists('esc_period', $operation)
&& !validateTimeUnit($operation['esc_period'], SEC_PER_MIN, SEC_PER_WEEK, true, $error,
['usermacros' => true])) {
error(_s('Incorrect value for field "%1$s": %2$s.', _('Step duration'), $error));
return false;
}
}
switch ($operationtype) {
case OPERATION_TYPE_MESSAGE:
$has_users = array_key_exists('opmessage_usr', $operation) && $operation['opmessage_usr'];
$has_usrgrps = array_key_exists('opmessage_grp', $operation) && $operation['opmessage_grp'];
if (!$has_users && !$has_usrgrps) {
error(_('No recipients specified for action operation message.'));
return false;
}
// break; is not missing here
case OPERATION_TYPE_UPDATE_MESSAGE:
$message = array_key_exists('opmessage', $operation) ? $operation['opmessage'] : [];
if (array_key_exists('default_msg', $message)
&& (!$default_msg_validator->validate($message['default_msg']))) {
error(_s('Incorrect value "%1$s" for "%2$s" field.', $message['default_msg'], _('Custom message')));
return false;
}
break;
case OPERATION_TYPE_COMMAND:
$scriptid = preg_replace('[\D]', '', $operation['operationtype']);
$operation['opcommand'] = ['scriptid' => $scriptid];
if (!array_key_exists('scriptid', $operation['opcommand']) || !$operation['opcommand']['scriptid']) {
error(_('No script specified for action operation command.'));
return false;
}
if ($eventsource == EVENT_SOURCE_SERVICE) {
break;
}
$has_groups = array_key_exists('opcommand_grp', $operation) && $operation['opcommand_grp'];
$has_hosts = array_key_exists('opcommand_hst', $operation) && $operation['opcommand_hst'];
if (!$has_groups && !$has_hosts) {
error(_('No targets specified for action operation global script.'));
return false;
}
break;
case OPERATION_TYPE_GROUP_ADD:
case OPERATION_TYPE_GROUP_REMOVE:
if (!array_key_exists('opgroup', $operation) || !$operation['opgroup']) {
error(_('Operation has no group to operate.'));
return false;
}
break;
case OPERATION_TYPE_TEMPLATE_ADD:
case OPERATION_TYPE_TEMPLATE_REMOVE:
if (!array_key_exists('optemplate', $operation) || !$operation['optemplate']) {
error(_('Operation has no template to operate.'));
return false;
}
break;
case OPERATION_TYPE_HOST_INVENTORY:
if (!array_key_exists('opinventory', $operation)
|| !array_key_exists('inventory_mode', $operation['opinventory'])) {
error(_('No inventory mode specified for action operation.'));
return false;
}
if ($operation['opinventory']['inventory_mode'] != HOST_INVENTORY_MANUAL
&& $operation['opinventory']['inventory_mode'] != HOST_INVENTORY_AUTOMATIC) {
error(_('Incorrect inventory mode in action operation.'));
return false;
}
break;
case OPERATION_TYPE_HOST_TAGS_ADD:
case OPERATION_TYPE_HOST_TAGS_REMOVE:
// At least one tag must exist with name and must be unique. Skips checking completely empty rows.
$tags = [];
if (array_key_exists('optag', $operation)) {
foreach ($operation['optag'] as $optag) {
$tag = trim($optag['tag']);
$value = trim($optag['value']);
if ($tag === '' && $value === '') {
continue;
}
if ($tag === '' && $value !== '') {
error(_s('Incorrect value for field "%1$s": %2$s.', _('Tag'), _('cannot be empty')));
return false;
}
if (array_key_exists($tag, $tags) && $tags[$tag] === $value) {
error(_s('Incorrect value for field "%1$s": %2$s.', _('Tag'),
_s('value "%1$s" already exists', '(tag, value)=('.$tag.', '.$value.')'))
);
return false;
}
$tags[$tag] = $value;
}
}
if (!$tags) {
error(_s('Incorrect value for field "%1$s": %2$s.', _('Tag'), _('cannot be empty')));
return false;
}
break;
}
return true;
}
protected function checkPermissions(): bool {
if ($this->getUserType() >= USER_TYPE_ZABBIX_ADMIN) {
if (!$this->getInput('actionid', '0')) {
return true;
}
return (bool) API::Action()->get([
'output' => [],
'actionids' => $this->getInput('actionid')
]);
}
return false;
}
protected function doAction(): void {
$operation = $this->getInput('operation');
if (preg_match('/\bscriptid\b/', $operation['operationtype'])) {
$operation['opcommand']['scriptid'] = preg_replace('[\D]', '', $operation['operationtype']);
$operationtype = OPERATION_TYPE_COMMAND;
if (array_key_exists('opcommand_hst', $operation)) {
foreach ($operation['opcommand_hst'] as $host) {
if (is_array($host['hostid']) && array_key_exists('current_host', $host['hostid'])) {
$operation['opcommand_hst'][0]['hostid'] = 0;
}
}
}
}
else {
$operationtype = (int) preg_replace('[\D]', '', $operation['operationtype']);
}
if (array_key_exists('opmessage', $operation)) {
if (!array_key_exists('default_msg', $operation['opmessage'])
&& ($operationtype == OPERATION_TYPE_MESSAGE
|| $operationtype == OPERATION_TYPE_RECOVERY_MESSAGE
|| $operationtype == OPERATION_TYPE_UPDATE_MESSAGE)) {
$operation['opmessage']['default_msg'] = '1';
unset($operation['opmessage']['subject'], $operation['opmessage']['message']);
}
}
// When tags are added or removed, trim tag names and values, and remove empty rows.
if ($operationtype == OPERATION_TYPE_HOST_TAGS_ADD || $operationtype == OPERATION_TYPE_HOST_TAGS_REMOVE) {
foreach ($operation['optag'] as $idx => &$optag) {
$tag = trim($optag['tag']);
$value = trim($optag['value']);
if ($tag === '' && $value === '') {
unset($operation['optag'][$idx]);
continue;
}
$optag['tag'] = $tag;
$optag['value'] = $value;
}
unset($optag);
}
$operation['operationtype'] = $operationtype;
$data['operation'] = $operation;
$data['operation']['row_index'] = $this->getInput('row_index');
$this->setResponse(new CControllerResponseData(['main_block' => json_encode($data)]));
}
}