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.

1532 lines
47 KiB

<?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.
**/
/**
* User roles API implementation.
*/
class CRole extends CApiService {
public const ACCESS_RULES = [
'get' => ['min_user_type' => USER_TYPE_ZABBIX_USER],
'create' => ['min_user_type' => USER_TYPE_SUPER_ADMIN],
'update' => ['min_user_type' => USER_TYPE_SUPER_ADMIN],
'delete' => ['min_user_type' => USER_TYPE_SUPER_ADMIN]
];
protected $tableName = 'role';
protected $tableAlias = 'r';
protected $sortColumns = ['roleid', 'name'];
/**
* Rule types.
*/
private const RULE_TYPE_INT32 = 0;
private const RULE_TYPE_STR = 1;
private const RULE_TYPE_MODULE = 2;
private const RULE_TYPE_SERVICE = 3;
/**
* Rule type correspondence to the database field names.
*/
public const RULE_TYPE_FIELDS = [
self::RULE_TYPE_INT32 => 'value_int',
self::RULE_TYPE_STR => 'value_str',
self::RULE_TYPE_MODULE => 'value_moduleid',
self::RULE_TYPE_SERVICE => 'value_serviceid'
];
/**
* @param array $options
*
* @return array|int
*
* @throws APIException
*/
public function get(array $options = []) {
$api_input_rules = ['type' => API_OBJECT, 'fields' => [
// filter
'roleids' => ['type' => API_IDS, 'flags' => API_ALLOW_NULL | API_NORMALIZE, 'default' => null],
'filter' => ['type' => API_FILTER, 'flags' => API_ALLOW_NULL, 'default' => null, 'fields' => ['roleid', 'name', 'type', 'readonly']],
'search' => ['type' => API_FILTER, 'flags' => API_ALLOW_NULL, 'default' => null, 'fields' => ['name']],
'searchByAny' => ['type' => API_BOOLEAN, 'default' => false],
'startSearch' => ['type' => API_FLAG, 'default' => false],
'excludeSearch' => ['type' => API_FLAG, 'default' => false],
'searchWildcardsEnabled' => ['type' => API_BOOLEAN, 'default' => false],
// output
'output' => ['type' => API_OUTPUT, 'in' => implode(',', ['roleid', 'name', 'type', 'readonly']), 'default' => API_OUTPUT_EXTEND],
'countOutput' => ['type' => API_FLAG, 'default' => false],
'selectRules' => ['type' => API_OUTPUT, 'flags' => API_ALLOW_NULL, 'in' => implode(',', ['ui', 'ui.default_access', 'services.read.mode', 'services.read.list', 'services.read.tag', 'services.write.mode', 'services.write.list', 'services.write.tag', 'modules', 'modules.default_access', 'api.access', 'api.mode', 'api', 'actions', 'actions.default_access']), 'default' => null],
'selectUsers' => ['type' => API_OUTPUT, 'flags' => API_ALLOW_NULL | API_ALLOW_COUNT, 'in' => implode(',', ['userid', 'username', 'name', 'surname', 'url', 'autologin', 'autologout', 'lang', 'refresh', 'theme', 'attempt_failed', 'attempt_ip', 'attempt_clock', 'rows_per_page', 'timezone', 'roleid']), 'default' => null],
// sort and limit
'sortfield' => ['type' => API_STRINGS_UTF8, 'flags' => API_NORMALIZE, 'in' => implode(',', $this->sortColumns), 'uniq' => true, 'default' => []],
'sortorder' => ['type' => API_SORTORDER, 'default' => []],
'limit' => ['type' => API_INT32, 'flags' => API_ALLOW_NULL, 'in' => '1:'.ZBX_MAX_INT32, 'default' => null],
// flags
'editable' => ['type' => API_BOOLEAN, 'default' => false],
'preservekeys' => ['type' => API_BOOLEAN, 'default' => false]
]];
if (!CApiInputValidator::validate($api_input_rules, $options, '/', $error)) {
self::exception(ZBX_API_ERROR_PARAMETERS, $error);
}
if ($options['editable'] && self::$userData['type'] != USER_TYPE_SUPER_ADMIN) {
return $options['countOutput'] ? '0' : [];
}
$db_roles = [];
$sql = $this->createSelectQuery('role', $options);
$resource = DBselect($sql, $options['limit']);
while ($row = DBfetch($resource)) {
if ($options['countOutput']) {
return $row['rowscount'];
}
$db_roles[$row['roleid']] = $row;
}
if ($db_roles) {
$db_roles = $this->addRelatedObjects($options, $db_roles);
$db_roles = $this->unsetExtraFields($db_roles, ['roleid', 'type'], $options['output']);
if (!$options['preservekeys']) {
$db_roles = array_values($db_roles);
}
}
return $db_roles;
}
/**
* @param array $roles
*
* @return array
*
* @throws APIException
*/
public function create(array $roles): array {
if (self::$userData['type'] != USER_TYPE_SUPER_ADMIN) {
self::exception(ZBX_API_ERROR_PERMISSIONS,
_s('No permissions to call "%1$s.%2$s".', 'role', __FUNCTION__)
);
}
$this->validateCreate($roles);
$ins_roles = [];
foreach ($roles as $role) {
unset($role['rules']);
$ins_roles[] = $role;
}
$roleids = DB::insert('role', $ins_roles);
$roles = array_combine($roleids, $roles);
$this->updateRules($roles);
foreach ($roles as $roleid => &$role) {
$role['roleid'] = $roleid;
}
unset($role);
$this->addAuditBulk(CAudit::ACTION_ADD, CAudit::RESOURCE_USER_ROLE, $roles);
return ['roleids' => $roleids];
}
/**
* @param array $roles
*
* @throws APIException
*/
private function validateCreate(array &$roles): void {
$api_input_rules = ['type' => API_OBJECTS, 'flags' => API_NOT_EMPTY | API_NORMALIZE, 'uniq' => [['name']], 'fields' => [
'name' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED | API_NOT_EMPTY, 'length' => DB::getFieldLength('role', 'name')],
'type' => ['type' => API_INT32, 'flags' => API_REQUIRED, 'in' => implode(',', [USER_TYPE_ZABBIX_USER, USER_TYPE_ZABBIX_ADMIN, USER_TYPE_SUPER_ADMIN])],
'rules' => ['type' => API_OBJECT, 'default' => [], 'fields' => [
'ui' => ['type' => API_OBJECTS, 'flags' => API_NORMALIZE, 'fields' => [
'name' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED, 'length' => DB::getFieldLength('role_rule', 'value_str')],
'status' => ['type' => API_INT32, 'in' => ZBX_ROLE_RULE_DISABLED.','.ZBX_ROLE_RULE_ENABLED, 'default' => ZBX_ROLE_RULE_ENABLED]
]],
'ui.default_access' => ['type' => API_INT32, 'in' => ZBX_ROLE_RULE_DISABLED.','.ZBX_ROLE_RULE_ENABLED],
'services.read.mode' => ['type' => API_INT32, 'in' => ZBX_ROLE_RULE_SERVICES_ACCESS_CUSTOM.','.ZBX_ROLE_RULE_SERVICES_ACCESS_ALL],
'services.read.list' => ['type' => API_OBJECTS, 'flags' => API_NORMALIZE, 'fields' => [
'serviceid' => ['type' => API_ID, 'flags' => API_REQUIRED]
]],
'services.read.tag' => ['type' => API_OBJECT, 'fields' => [
'tag' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED, 'length' => DB::getFieldLength('role_rule', 'value_str')],
'value' => ['type' => API_STRING_UTF8, 'length' => DB::getFieldLength('role_rule', 'value_str'), 'default' => '']
]],
'services.write.mode' => ['type' => API_INT32, 'in' => ZBX_ROLE_RULE_SERVICES_ACCESS_CUSTOM.','.ZBX_ROLE_RULE_SERVICES_ACCESS_ALL],
'services.write.list' => ['type' => API_OBJECTS, 'flags' => API_NORMALIZE, 'fields' => [
'serviceid' => ['type' => API_ID, 'flags' => API_REQUIRED]
]],
'services.write.tag' => ['type' => API_OBJECT, 'fields' => [
'tag' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED, 'length' => DB::getFieldLength('role_rule', 'value_str')],
'value' => ['type' => API_STRING_UTF8, 'length' => DB::getFieldLength('role_rule', 'value_str'), 'default' => '']
]],
'modules' => ['type' => API_OBJECTS, 'flags' => API_NORMALIZE, 'fields' => [
'moduleid' => ['type' => API_ID, 'flags' => API_REQUIRED],
'status' => ['type' => API_INT32, 'in' => ZBX_ROLE_RULE_DISABLED.','.ZBX_ROLE_RULE_ENABLED, 'default' => ZBX_ROLE_RULE_ENABLED]
]],
'modules.default_access' => ['type' => API_INT32, 'in' => ZBX_ROLE_RULE_DISABLED.','.ZBX_ROLE_RULE_ENABLED],
'api' => ['type' => API_STRINGS_UTF8, 'flags' => API_NORMALIZE, 'uniq' => true],
'api.access' => ['type' => API_INT32, 'in' => ZBX_ROLE_RULE_DISABLED.','.ZBX_ROLE_RULE_ENABLED],
'api.mode' => ['type' => API_INT32, 'in' => ZBX_ROLE_RULE_API_MODE_DENY.','.ZBX_ROLE_RULE_API_MODE_ALLOW],
'actions' => ['type' => API_OBJECTS, 'flags' => API_NORMALIZE, 'fields' => [
'name' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED, 'length' => DB::getFieldLength('role_rule', 'value_str')],
'status' => ['type' => API_INT32, 'in' => ZBX_ROLE_RULE_DISABLED.','.ZBX_ROLE_RULE_ENABLED, 'default' => ZBX_ROLE_RULE_ENABLED]
]],
'actions.default_access' => ['type' => API_INT32, 'in' => ZBX_ROLE_RULE_DISABLED.','.ZBX_ROLE_RULE_ENABLED, 'default' => ZBX_ROLE_RULE_ENABLED]
]]
]];
if (!CApiInputValidator::validate($api_input_rules, $roles, '/', $error)) {
self::exception(ZBX_API_ERROR_PARAMETERS, $error);
}
$this->checkDuplicates($roles);
$this->checkRules($roles);
}
/**
* @param array $roles
*
* @return array
*
* @throws APIException
*/
public function update(array $roles): array {
if (self::$userData['type'] != USER_TYPE_SUPER_ADMIN) {
self::exception(ZBX_API_ERROR_PERMISSIONS,
_s('No permissions to call "%1$s.%2$s".', 'role', __FUNCTION__)
);
}
$this->validateUpdate($roles, $db_roles);
$upd_roles = [];
foreach ($roles as $role) {
$upd_role = DB::getUpdatedValues('role', $role, $db_roles[$role['roleid']]);
if ($upd_role) {
$upd_roles[] = [
'values' => $upd_role,
'where' => ['roleid' => $role['roleid']]
];
}
}
if ($upd_roles) {
DB::update('role', $upd_roles);
}
$roles = array_column($roles, null, 'roleid');
$this->updateRules($roles, $db_roles);
$this->addAuditBulk(CAudit::ACTION_UPDATE, CAudit::RESOURCE_USER_ROLE, $roles, $db_roles);
return ['roleids' => array_column($roles, 'roleid')];
}
/**
* @param array $roles
* @param array|null $db_roles
*
* @throws APIException
*/
private function validateUpdate(array &$roles, ?array &$db_roles): void {
$api_input_rules = ['type' => API_OBJECTS, 'flags' => API_NOT_EMPTY | API_NORMALIZE, 'uniq' => [['name']], 'fields' => [
'roleid' => ['type' => API_ID, 'flags' => API_REQUIRED],
'name' => ['type' => API_STRING_UTF8, 'flags' => API_NOT_EMPTY, 'length' => DB::getFieldLength('role', 'name')],
'type' => ['type' => API_INT32, 'in' => implode(',', [USER_TYPE_ZABBIX_USER, USER_TYPE_ZABBIX_ADMIN, USER_TYPE_SUPER_ADMIN])],
'rules' => ['type' => API_OBJECT, 'fields' => [
'ui' => ['type' => API_OBJECTS, 'flags' => API_NORMALIZE, 'fields' => [
'name' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED, 'length' => DB::getFieldLength('role_rule', 'value_str')],
'status' => ['type' => API_INT32, 'in' => ZBX_ROLE_RULE_DISABLED.','.ZBX_ROLE_RULE_ENABLED, 'default' => ZBX_ROLE_RULE_ENABLED]
]],
'ui.default_access' => ['type' => API_INT32, 'in' => ZBX_ROLE_RULE_DISABLED.','.ZBX_ROLE_RULE_ENABLED],
'services.read.mode' => ['type' => API_INT32, 'in' => ZBX_ROLE_RULE_SERVICES_ACCESS_CUSTOM.','.ZBX_ROLE_RULE_SERVICES_ACCESS_ALL],
'services.read.list' => ['type' => API_OBJECTS, 'flags' => API_NORMALIZE, 'fields' => [
'serviceid' => ['type' => API_ID, 'flags' => API_REQUIRED]
]],
'services.read.tag' => ['type' => API_OBJECT, 'fields' => [
'tag' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED, 'length' => DB::getFieldLength('role_rule', 'value_str')],
'value' => ['type' => API_STRING_UTF8, 'length' => DB::getFieldLength('role_rule', 'value_str'), 'default' => '']
]],
'services.write.mode' => ['type' => API_INT32, 'in' => ZBX_ROLE_RULE_SERVICES_ACCESS_CUSTOM.','.ZBX_ROLE_RULE_SERVICES_ACCESS_ALL],
'services.write.list' => ['type' => API_OBJECTS, 'flags' => API_NORMALIZE, 'fields' => [
'serviceid' => ['type' => API_ID, 'flags' => API_REQUIRED]
]],
'services.write.tag' => ['type' => API_OBJECT, 'fields' => [
'tag' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED, 'length' => DB::getFieldLength('role_rule', 'value_str')],
'value' => ['type' => API_STRING_UTF8, 'length' => DB::getFieldLength('role_rule', 'value_str'), 'default' => '']
]],
'modules' => ['type' => API_OBJECTS, 'flags' => API_NORMALIZE, 'fields' => [
'moduleid' => ['type' => API_ID, 'flags' => API_REQUIRED],
'status' => ['type' => API_INT32, 'in' => ZBX_ROLE_RULE_DISABLED.','.ZBX_ROLE_RULE_ENABLED, 'default' => ZBX_ROLE_RULE_ENABLED]
]],
'modules.default_access' => ['type' => API_INT32, 'in' => ZBX_ROLE_RULE_DISABLED.','.ZBX_ROLE_RULE_ENABLED],
'api' => ['type' => API_STRINGS_UTF8, 'flags' => API_NORMALIZE, 'uniq' => true],
'api.access' => ['type' => API_INT32, 'in' => ZBX_ROLE_RULE_DISABLED.','.ZBX_ROLE_RULE_ENABLED],
'api.mode' => ['type' => API_INT32, 'in' => ZBX_ROLE_RULE_API_MODE_DENY.','.ZBX_ROLE_RULE_API_MODE_ALLOW],
'actions' => ['type' => API_OBJECTS, 'flags' => API_NORMALIZE, 'fields' => [
'name' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED, 'length' => DB::getFieldLength('role_rule', 'value_str')],
'status' => ['type' => API_INT32, 'in' => ZBX_ROLE_RULE_DISABLED.','.ZBX_ROLE_RULE_ENABLED, 'default' => ZBX_ROLE_RULE_ENABLED]
]],
'actions.default_access' => ['type' => API_INT32, 'in' => ZBX_ROLE_RULE_DISABLED.','.ZBX_ROLE_RULE_ENABLED]
]]
]];
if (!CApiInputValidator::validate($api_input_rules, $roles, '/', $error)) {
self::exception(ZBX_API_ERROR_PARAMETERS, $error);
}
$db_roles = $this->get([
'output' => ['roleid', 'name', 'type', 'readonly'],
'roleids' => array_column($roles, 'roleid'),
'selectRules' => ['ui', 'ui.default_access', 'services.read.mode', 'services.read.list',
'services.read.tag', 'services.write.mode', 'services.write.list', 'services.write.tag', 'modules',
'modules.default_access', 'api.access', 'api.mode', 'api', 'actions', 'actions.default_access'
],
'preservekeys' => true
]);
if (count($db_roles) != count($roles)) {
self::exception(ZBX_API_ERROR_PERMISSIONS, _('No permissions to referred object or it does not exist!'));
}
$this->checkDuplicates($roles, $db_roles);
$this->checkRules($roles, $db_roles);
$this->checkReadonly($db_roles);
$this->checkOwnRoleType($roles);
}
/**
* @param array $roleids
*
* @return array
*
* @throws APIException
*/
public function delete(array $roleids): array {
if (self::$userData['type'] != USER_TYPE_SUPER_ADMIN) {
self::exception(ZBX_API_ERROR_PERMISSIONS,
_s('No permissions to call "%1$s.%2$s".', 'role', __FUNCTION__)
);
}
$api_input_rules = ['type' => API_IDS, 'flags' => API_NOT_EMPTY, 'uniq' => true];
if (!CApiInputValidator::validate($api_input_rules, $roleids, '/', $error)) {
self::exception(ZBX_API_ERROR_PARAMETERS, $error);
}
$db_roles = $this->get([
'output' => ['roleid', 'name', 'readonly'],
'selectUsers' => ['userid'],
'roleids' => $roleids,
'preservekeys' => true
]);
if (count($db_roles) != count($roleids)) {
self::exception(ZBX_API_ERROR_PERMISSIONS, _('No permissions to referred object or it does not exist!'));
}
foreach ($db_roles as $db_role) {
if ($db_role['readonly'] == 1) {
self::exception(ZBX_API_ERROR_PERMISSIONS,
_s('Cannot delete readonly user role "%1$s".', $db_role['name'])
);
}
if ($db_role['users']) {
self::exception(ZBX_API_ERROR_PERMISSIONS,
_s('Cannot delete assigned user role "%1$s".', $db_role['name'])
);
}
}
DB::delete('role', ['roleid' => $roleids]);
$this->addAuditBulk(CAudit::ACTION_DELETE, CAudit::RESOURCE_USER_ROLE, $db_roles);
return ['roleids' => $roleids];
}
/**
* @param array $roles
* @param array|null $db_roles
*
* @throws APIException
*/
private function checkDuplicates(array $roles, array $db_roles = null): void {
$names = [];
foreach ($roles as $role) {
if ($db_roles === null
|| (array_key_exists('name', $role) && $role['name'] !== $db_roles[$role['roleid']]['name'])) {
$names[] = $role['name'];
}
}
if (!$names) {
return;
}
$duplicate = DB::select('role', [
'output' => ['name'],
'filter' => ['name' => $names],
'limit' => 1
]);
if ($duplicate) {
self::exception(ZBX_API_ERROR_PARAMETERS, _s('User role "%1$s" already exists.', $duplicate[0]['name']));
}
}
/**
* Check user role rules.
*
* @param array $roles
* @param array|null $db_roles
*
* @throws APIException if input is invalid.
*/
private function checkRules(array $roles, array $db_roles = null): void {
foreach ($roles as $role) {
if (!array_key_exists('rules', $role)) {
continue;
}
$name = $db_roles !== null ? $db_roles[$role['roleid']]['name'] : $role['name'];
$type = array_key_exists('type', $role) ? $role['type'] : $db_roles[$role['roleid']]['type'];
$db_rules = $db_roles !== null ? $db_roles[$role['roleid']]['rules'] : null;
$this->checkUiRules($name, (int) $type, $role['rules'], $db_rules);
$this->checkServicesRules($name, (int) $type, $role['rules'], $db_rules);
$this->checkModulesRules($name, $role['rules']);
$this->checkApiRules($name, $role['rules']);
$this->checkActionsRules($name, (int) $type, $role['rules']);
}
}
/**
* @param string $name
* @param int $type
* @param array $rules
* @param array|null $db_rules
* @throws APIException
*/
private function checkUiRules(string $name, int $type, array $rules, array $db_rules = null): void {
if (!array_key_exists('ui', $rules)) {
return;
}
if (array_key_exists('ui.default_access', $rules)) {
$default_access = $rules['ui.default_access'];
}
elseif ($db_rules !== null) {
$default_access = $db_rules['ui.default_access'];
}
else {
$default_access = ZBX_ROLE_RULE_ENABLED;
}
$ui_rules = [];
foreach (CRoleHelper::getUiElementsByUserType($type) as $ui_element) {
$ui_rule_name = substr($ui_element, strlen('ui.'));
$ui_rules[$ui_rule_name] = $default_access == ZBX_ROLE_RULE_ENABLED;
}
foreach ($rules['ui'] as $ui_rule) {
if (!array_key_exists($ui_rule['name'], $ui_rules)) {
self::exception(ZBX_API_ERROR_PARAMETERS,
_s('UI element "%2$s" is not available for user role "%1$s".', $name, $ui_rule['name'])
);
}
$ui_rules[$ui_rule['name']] = $ui_rule['status'] == ZBX_ROLE_RULE_ENABLED;
}
if (!in_array(true, $ui_rules)) {
self::exception(ZBX_API_ERROR_PARAMETERS,
_s('At least one UI element must be enabled for user role "%1$s".', $name)
);
}
}
/**
* @param string $name
* @param int $type
* @param array $rules
* @param array|null $db_rules
*
* @throws APIException
*/
private function checkServicesRules(string $name, int $type, array $rules, array $db_rules = null): void {
$this->checkServicesReadRules($name, $rules, $db_rules);
$this->checkServicesWriteRules($name, $type, $rules, $db_rules);
$list = [];
if (array_key_exists('services.read.list', $rules)) {
$list = array_merge($list, $rules['services.read.list']);
}
elseif ($db_rules !== null) {
$list = array_merge($list, $db_rules['services.read.list']);
}
if (array_key_exists('services.write.list', $rules)) {
$list = array_merge($list, $rules['services.write.list']);
}
elseif ($db_rules !== null) {
$list = array_merge($list, $db_rules['services.write.list']);
}
if (!$list) {
return;
}
$serviceids = array_unique(array_column($list, 'serviceid'));
$db_services = DB::select('services', [
'output' => ['serviceid'],
'serviceids' => $serviceids,
'preservekeys' => true
]);
$unavailable_serviceids = array_diff($serviceids, array_keys($db_services));
if ($unavailable_serviceids) {
self::exception(ZBX_API_ERROR_PARAMETERS,
_s('Service with ID "%2$s" is not available for user role "%1$s".', $name, $unavailable_serviceids[0])
);
}
}
/**
* @param string $name
* @param array $rules
* @param array|null $db_rules
* @throws APIException
*/
private function checkServicesReadRules(string $name, array $rules, array $db_rules = null): void {
if (!array_key_exists('services.read.mode', $rules)
&& !array_key_exists('services.read.list', $rules)
&& !array_key_exists('services.read.tag', $rules)) {
return;
}
if (array_key_exists('services.read.mode', $rules)) {
$mode = $rules['services.read.mode'];
}
elseif ($db_rules !== null) {
$mode = $db_rules['services.read.mode'];
}
else {
$mode = ZBX_ROLE_RULE_SERVICES_ACCESS_ALL;
}
if ($mode == ZBX_ROLE_RULE_SERVICES_ACCESS_CUSTOM) {
if (array_key_exists('services.read.tag', $rules)) {
if ($rules['services.read.tag']['tag'] === '' && $rules['services.read.tag']['value'] !== '') {
self::exception(ZBX_API_ERROR_PARAMETERS, _s(
'Cannot have non-empty tag value while having empty tag in rule "%2$s" for user role "%1$s".',
$name, 'services.read.tag'
));
}
}
return;
}
if (array_key_exists('services.read.list', $rules)) {
$has_list = (bool) $rules['services.read.list'];
}
elseif ($db_rules !== null) {
$has_list = (bool) $db_rules['services.read.list'];
}
else {
$has_list = false;
}
if ($has_list) {
self::exception(ZBX_API_ERROR_PARAMETERS, _s(
'Cannot have non-default "%2$s" rule while having "%3$s" set to %4$d for user role "%1$s".',
$name, 'services.read.list', 'services.read.mode', ZBX_ROLE_RULE_SERVICES_ACCESS_ALL
));
}
if (array_key_exists('services.read.tag', $rules)) {
$has_tag = $rules['services.read.tag']['tag'] !== '';
}
elseif ($db_rules !== null) {
$has_tag = $db_rules['services.read.tag']['tag'] !== '';
}
else {
$has_tag = false;
}
if ($has_tag) {
self::exception(ZBX_API_ERROR_PARAMETERS, _s(
'Cannot have non-default "%2$s" rule while having "%3$s" set to %4$d for user role "%1$s".',
$name, 'services.read.tag', 'services.read.mode', ZBX_ROLE_RULE_SERVICES_ACCESS_ALL
));
}
}
/**
* @param string $name
* @param int $type
* @param array $rules
* @param array|null $db_rules
* @throws APIException
*/
private function checkServicesWriteRules(string $name, int $type, array $rules, array $db_rules = null): void {
if (!array_key_exists('services.write.mode', $rules)
&& !array_key_exists('services.write.list', $rules)
&& !array_key_exists('services.write.tag', $rules)) {
return;
}
if (array_key_exists('services.write.mode', $rules)) {
$mode = $rules['services.write.mode'];
}
elseif ($db_rules !== null) {
$mode = $db_rules['services.write.mode'];
}
elseif (self::$userData['type'] == USER_TYPE_SUPER_ADMIN || self::$userData['type'] == USER_TYPE_ZABBIX_ADMIN) {
$mode = ZBX_ROLE_RULE_SERVICES_ACCESS_ALL;
}
else {
$mode = ZBX_ROLE_RULE_SERVICES_ACCESS_CUSTOM;
}
if ($mode == ZBX_ROLE_RULE_SERVICES_ACCESS_CUSTOM) {
if (array_key_exists('services.write.tag', $rules)) {
if ($rules['services.write.tag']['tag'] === '' && $rules['services.write.tag']['value'] !== '') {
self::exception(ZBX_API_ERROR_PARAMETERS, _s(
'Cannot have non-empty tag value while having empty tag in rule "%2$s" for user role "%1$s".',
$name, 'services.write.tag'
));
}
}
return;
}
if (array_key_exists('services.write.list', $rules)) {
$has_list = (bool) $rules['services.write.list'];
}
elseif ($db_rules !== null) {
$has_list = (bool) $db_rules['services.write.list'];
}
else {
$has_list = false;
}
if ($has_list) {
self::exception(ZBX_API_ERROR_PARAMETERS, _s(
'Cannot have non-default "%2$s" rule while having "%3$s" set to %4$d for user role "%1$s".',
$name, 'services.write.list', 'services.write.mode', ZBX_ROLE_RULE_SERVICES_ACCESS_ALL
));
}
if (array_key_exists('services.write.tag', $rules)) {
$has_tag = $rules['services.write.tag']['tag'] !== '';
}
elseif ($db_rules !== null) {
$has_tag = $db_rules['services.write.tag']['tag'] !== '';
}
else {
$has_tag = false;
}
if ($has_tag) {
self::exception(ZBX_API_ERROR_PARAMETERS, _s(
'Cannot have non-default "%2$s" rule while having "%3$s" set to %4$d for user role "%1$s".',
$name, 'services.write.tag', 'services.write.mode', ZBX_ROLE_RULE_SERVICES_ACCESS_ALL
));
}
}
/**
* @param string $name
* @param array $rules
*
* @throws APIException
*/
private function checkModulesRules(string $name, array $rules): void {
if (!array_key_exists('modules', $rules)) {
return;
}
$moduleids = [];
foreach ($rules['modules'] as $module) {
$moduleids[$module['moduleid']] = true;
}
if (!$moduleids) {
return;
}
$unavailable_moduleids = array_diff(array_keys($moduleids), self::getModuleIds());
if ($unavailable_moduleids) {
self::exception(ZBX_API_ERROR_PARAMETERS,
_s('Module with ID "%2$s" is not available for user role "%1$s".', $name, $unavailable_moduleids[0])
);
}
}
/**
* @param string $name
* @param array $rules
*
* @throws APIException
*/
private function checkApiRules(string $name, array $rules): void {
if (!array_key_exists('api', $rules)) {
return;
}
foreach ($rules['api'] as $rule) {
if ($rule === ZBX_ROLE_RULE_API_WILDCARD || $rule === ZBX_ROLE_RULE_API_WILDCARD_ALIAS) {
continue;
}
if (!in_array($rule, CRoleHelper::getApiMethodMasks(USER_TYPE_SUPER_ADMIN), true)
&& !in_array($rule, CRoleHelper::getApiMethods(USER_TYPE_SUPER_ADMIN), true)) {
self::exception(ZBX_API_ERROR_PARAMETERS,
_s('Invalid API method "%2$s" for user role "%1$s".', $name, $rule)
);
}
}
}
/**
* @param string $name
* @param int $type
* @param array $rules
*
* @throws APIException
*/
private function checkActionsRules(string $name, int $type, array $rules): void {
if (!array_key_exists('actions', $rules)) {
return;
}
$all_actions = CRoleHelper::getActionsByUserType($type);
foreach ($rules['actions'] as $rule) {
if (!in_array('actions.'.$rule['name'], $all_actions)) {
self::exception(ZBX_API_ERROR_PARAMETERS,
_s('Action "%2$s" is not available for user role "%1$s".', $name, $rule['name'])
);
}
}
}
/**
* @param array $db_roles
*
* @throws APIException
*/
private function checkReadonly(array $db_roles): void {
foreach ($db_roles as $db_role) {
if ($db_role['readonly'] == 1) {
self::exception(ZBX_API_ERROR_PERMISSIONS, _s('Cannot update readonly user role "%1$s".',
$db_role['name']
));
}
}
}
/**
* @param array $roles
*
* @throws APIException
*/
private function checkOwnRoleType(array $roles): void {
$role_types = array_column($roles, 'type', 'roleid');
if (array_key_exists(self::$userData['roleid'], $role_types)
&& $role_types[self::$userData['roleid']] != self::$userData['type']) {
self::exception(ZBX_API_ERROR_PERMISSIONS, _('Cannot change the user type of own role.'));
}
}
/**
* @param array $roles
* @param array|null $db_roles
*
* @throws APIException
*/
private function updateRules(array $roles, array $db_roles = null): void {
$default_rules = [
'ui' => [],
'ui.default_access' => ZBX_ROLE_RULE_ENABLED,
'services.read.mode' => ZBX_ROLE_RULE_SERVICES_ACCESS_ALL,
'services.read.list' => [],
'services.read.tag' => ['tag' => '', 'value' => ''],
'services.write.mode' => ZBX_ROLE_RULE_SERVICES_ACCESS_CUSTOM,
'services.write.list' => [],
'services.write.tag' => ['tag' => '', 'value' => ''],
'modules' => [],
'modules.default_access' => ZBX_ROLE_RULE_ENABLED,
'api' => [],
'api.access' => ZBX_ROLE_RULE_ENABLED,
'api.mode' => ZBX_ROLE_RULE_API_MODE_DENY,
'actions' => [],
'actions.default_access' => ZBX_ROLE_RULE_ENABLED
];
$rules = [];
foreach ($roles as $roleid => $role) {
if (!array_key_exists('rules', $role)) {
continue;
}
$type = array_key_exists('type', $role) ? $role['type'] : $db_roles[$role['roleid']]['type'];
$old_rules = $db_roles !== null ? $db_roles[$roleid]['rules'] : $default_rules;
$new_rules = $role['rules'] + $old_rules;
$rules[$roleid] = array_merge(
$this->compileUiRules((int) $type, $old_rules, $new_rules),
$this->compileServicesReadRules($new_rules),
$this->compileServicesWriteRules($new_rules),
$this->compileModulesRules($old_rules, $new_rules),
$this->compileApiRules($new_rules),
$this->compileActionsRules((int) $type, $old_rules, $new_rules)
);
}
$del_rules = [];
$ins_rules = [];
if ($db_roles !== null) {
$db_rules = DB::select('role_rule', [
'output' => ['role_ruleid', 'roleid', 'type', 'name', 'value_int', 'value_str', 'value_moduleid',
'value_serviceid'
],
'filter' => ['roleid' => array_keys($rules)]
]);
foreach ($db_rules as $db_rule) {
$value = $db_rule[self::RULE_TYPE_FIELDS[$db_rule['type']]];
$del_rules[$db_rule['roleid']][$db_rule['name']][$db_rule['type']][$value] = $db_rule['role_ruleid'];
}
}
foreach ($rules as $roleid => $role_rules) {
foreach ($role_rules as $rule) {
if (array_key_exists($roleid, $del_rules)
&& array_key_exists($rule['name'], $del_rules[$roleid])
&& array_key_exists($rule['type'], $del_rules[$roleid][$rule['name']])
&& array_key_exists($rule['value'], $del_rules[$roleid][$rule['name']][$rule['type']])) {
unset($del_rules[$roleid][$rule['name']][$rule['type']][$rule['value']]);
}
else {
$ins_rules[$rule['type']][] = [
'roleid' => $roleid,
'type' => $rule['type'],
'name' => $rule['name'],
self::RULE_TYPE_FIELDS[$rule['type']] => $rule['value']
];
}
}
}
if ($del_rules) {
$del_role_ruleids = [];
foreach ($del_rules as $del_rules) {
foreach ($del_rules as $del_rules) {
foreach ($del_rules as $del_rules) {
foreach ($del_rules as $role_ruleid) {
$del_role_ruleids[$role_ruleid] = true;
}
}
}
}
DB::delete('role_rule', ['role_ruleid' => array_keys($del_role_ruleids)]);
}
if ($ins_rules) {
foreach ($ins_rules as $ins_rules) {
DB::insertBatch('role_rule', $ins_rules);
}
}
}
/**
* @param int $type
* @param array $old_rules
* @param array $new_rules
*
* @return array
*/
private function compileUiRules(int $type, array $old_rules, array $new_rules): array {
$old_ui_rules = array_column($old_rules['ui'], null, 'name');
$new_ui_rules = array_column($new_rules['ui'], null, 'name');
$compiled_rules = [];
foreach (CRoleHelper::getUiElementsByUserType($type) as $ui_rule_name) {
$ui_element = substr($ui_rule_name, strlen('ui.'));
if (array_key_exists($ui_element, $new_ui_rules)) {
$ui_rule_status = $new_ui_rules[$ui_element]['status'];
}
elseif (array_key_exists($ui_element, $old_ui_rules)) {
$ui_rule_status = $old_ui_rules[$ui_element]['status'];
}
else {
$ui_rule_status = $old_rules['ui.default_access'];
}
if ($ui_rule_status != $new_rules['ui.default_access']) {
$compiled_rules[] = [
'name' => $ui_rule_name,
'type' => self::RULE_TYPE_INT32,
'value' => $ui_rule_status
];
}
}
$compiled_rules[] = [
'name' => 'ui.default_access',
'type' => self::RULE_TYPE_INT32,
'value' => $new_rules['ui.default_access']
];
return $compiled_rules;
}
/**
* @param array $new_rules
*
* @return array
*/
private function compileServicesReadRules(array $new_rules): array {
$compiled_rules[] = [
'name' => 'services.read',
'type' => self::RULE_TYPE_INT32,
'value' => $new_rules['services.read.mode']
];
if ($new_rules['services.read.mode'] == ZBX_ROLE_RULE_SERVICES_ACCESS_CUSTOM) {
foreach ($new_rules['services.read.list'] as $index => $service) {
$compiled_rules[] = [
'name' => 'services.read.id.'.$index,
'type' => self::RULE_TYPE_SERVICE,
'value' => $service['serviceid']
];
}
if ($new_rules['services.read.tag']['tag'] !== '') {
$compiled_rules[] = [
'name' => 'services.read.tag.name',
'type' => self::RULE_TYPE_STR,
'value' => $new_rules['services.read.tag']['tag']
];
if ($new_rules['services.read.tag']['value'] !== '') {
$compiled_rules[] = [
'name' => 'services.read.tag.value',
'type' => self::RULE_TYPE_STR,
'value' => $new_rules['services.read.tag']['value']
];
}
}
}
return $compiled_rules;
}
/**
* @param array $new_rules
*
* @return array
*/
private function compileServicesWriteRules(array $new_rules): array {
$compiled_rules[] = [
'name' => 'services.write',
'type' => self::RULE_TYPE_INT32,
'value' => $new_rules['services.write.mode']
];
if ($new_rules['services.write.mode'] == ZBX_ROLE_RULE_SERVICES_ACCESS_CUSTOM) {
foreach ($new_rules['services.write.list'] as $index => $service) {
$compiled_rules[] = [
'name' => 'services.write.id.'.$index,
'type' => self::RULE_TYPE_SERVICE,
'value' => $service['serviceid']
];
}
if ($new_rules['services.write.tag']['tag'] !== '') {
$compiled_rules[] = [
'name' => 'services.write.tag.name',
'type' => self::RULE_TYPE_STR,
'value' => $new_rules['services.write.tag']['tag']
];
if ($new_rules['services.write.tag']['value'] !== '') {
$compiled_rules[] = [
'name' => 'services.write.tag.value',
'type' => self::RULE_TYPE_STR,
'value' => $new_rules['services.write.tag']['value']
];
}
}
}
return $compiled_rules;
}
/**
* @param array $old_rules
* @param array $new_rules
*
* @return array
*
* @throws APIException
*/
private function compileModulesRules(array $old_rules, array $new_rules): array {
$old_modules_rules = array_column($old_rules['modules'], null, 'moduleid');
$new_modules_rules = array_column($new_rules['modules'], null, 'moduleid');
$compiled_rules = [];
$index = 0;
foreach (self::getModuleIds() as $moduleid) {
if (array_key_exists($moduleid, $new_modules_rules)) {
$module_status = $new_modules_rules[$moduleid]['status'];
}
elseif (array_key_exists($moduleid, $old_modules_rules)) {
$module_status = $old_modules_rules[$moduleid]['status'];
}
else {
$module_status = $old_rules['modules.default_access'];
}
if ($module_status != $new_rules['modules.default_access']) {
$compiled_rules[] = [
'name' => 'modules.module.'.$index,
'type' => self::RULE_TYPE_MODULE,
'value' => $moduleid
];
$index++;
}
}
$compiled_rules[] = [
'name' => 'modules.default_access',
'type' => self::RULE_TYPE_INT32,
'value' => $new_rules['modules.default_access']
];
return $compiled_rules;
}
/**
* @param array $new_rules
*
* @return array
*/
private function compileApiRules(array $new_rules): array {
$compiled_rules = [];
$compiled_rules[] = [
'name' => 'api.access',
'type' => self::RULE_TYPE_INT32,
'value' => $new_rules['api.access']
];
if ($new_rules['api.access'] == ZBX_ROLE_RULE_ENABLED) {
$compiled_rules[] = [
'name' => 'api.mode',
'type' => self::RULE_TYPE_INT32,
'value' => $new_rules['api.mode']
];
foreach ($new_rules['api'] as $index => $api_method) {
$compiled_rules[] = [
'name' => 'api.method.'.$index,
'type' => self::RULE_TYPE_STR,
'value' => $api_method
];
}
}
return $compiled_rules;
}
/**
* @param int $type
* @param array $old_rules
* @param array $new_rules
*
* @return array
*/
private function compileActionsRules(int $type, array $old_rules, array $new_rules): array {
$old_actions_rules = array_column($old_rules['actions'], null, 'name');
$new_actions_rules = array_column($new_rules['actions'], null, 'name');
$compiled_rules = [];
foreach (CRoleHelper::getActionsByUserType($type) as $action_rule_name) {
$action_element = substr($action_rule_name, strlen('actions.'));
if (array_key_exists($action_element, $new_actions_rules)) {
$action_rule_status = $new_actions_rules[$action_element]['status'];
}
elseif (array_key_exists($action_element, $old_actions_rules)) {
$action_rule_status = $old_actions_rules[$action_element]['status'];
}
else {
$action_rule_status = $old_rules['actions.default_access'];
}
if ($action_rule_status != $new_rules['actions.default_access']) {
$compiled_rules[] = [
'name' => $action_rule_name,
'type' => self::RULE_TYPE_INT32,
'value' => $action_rule_status
];
}
}
$compiled_rules[] = [
'name' => 'actions.default_access',
'type' => self::RULE_TYPE_INT32,
'value' => $new_rules['actions.default_access']
];
return $compiled_rules;
}
/**
* @param string $table_name
* @param string $table_alias
* @param array $options
* @param array $sql_parts
*
* @return array
*/
protected function applyQueryFilterOptions($table_name, $table_alias, array $options, array $sql_parts): array {
$sql_parts = parent::applyQueryFilterOptions($table_name, $table_alias, $options, $sql_parts);
if (self::$userData['type'] != USER_TYPE_SUPER_ADMIN) {
$sql_parts['from']['users'] = 'users u';
$sql_parts['where']['u'] = 'r.roleid=u.roleid';
$sql_parts['where'][] = 'u.userid='.self::$userData['userid'];
}
return $sql_parts;
}
/**
* @param string $table_name
* @param string $table_alias
* @param array $options
* @param array $sql_parts
*
* @return array
*/
protected function applyQueryOutputOptions($table_name, $table_alias, array $options, array $sql_parts): array {
$sql_parts = parent::applyQueryOutputOptions($table_name, $table_alias, $options, $sql_parts);
if (!$options['countOutput'] && $options['selectRules'] !== null) {
$sql_parts = $this->addQuerySelect('r.type', $sql_parts);
}
return $sql_parts;
}
/**
* @param array $options
* @param array $result
*
* @return array
*
* @throws APIException
*/
protected function addRelatedObjects(array $options, array $result): array {
$result = parent::addRelatedObjects($options, $result);
$roleids = array_keys($result);
if ($options['selectRules'] !== null) {
if ($options['selectRules'] === API_OUTPUT_EXTEND) {
$output = ['ui', 'ui.default_access', 'services.read.mode', 'services.read.list', 'services.read.tag',
'services.write.mode', 'services.write.list', 'services.write.tag', 'modules',
'modules.default_access', 'api', 'api.access', 'api.mode', 'actions', 'actions.default_access'
];
}
else {
$output = $options['selectRules'];
}
$rules = DB::select('role_rule', [
'output' => ['role_ruleid', 'roleid', 'type', 'name', 'value_int', 'value_str', 'value_moduleid',
'value_serviceid'
],
'filter' => ['roleid' => $roleids]
]);
$roles_rules = array_fill_keys($roleids, []);
foreach ($rules as $rule) {
$roles_rules[$rule['roleid']][$rule['name']] = $rule[self::RULE_TYPE_FIELDS[$rule['type']]];
}
foreach ($result as $roleid => &$role) {
$role['rules'] = array_merge(
$this->getRelatedUiRules($roles_rules[$roleid], $output, (int) $role['type']),
$this->getRelatedServicesReadRules($roles_rules[$roleid], $output),
$this->getRelatedServicesWriteRules($roles_rules[$roleid], $output),
$this->getRelatedModulesRules($roles_rules[$roleid], $output),
$this->getRelatedApiRules($roles_rules[$roleid], $output),
$this->getRelatedActionsRules($roles_rules[$roleid], $output, (int) $role['type'])
);
}
unset($role);
}
if ($options['selectUsers'] !== null) {
if ($options['selectUsers'] === API_OUTPUT_COUNT) {
$output = ['userid', 'roleid'];
}
elseif ($options['selectUsers'] === API_OUTPUT_EXTEND) {
$output = ['userid', 'username', 'name', 'surname', 'url', 'autologin', 'autologout', 'lang', 'refresh',
'theme', 'attempt_failed', 'attempt_ip', 'attempt_clock', 'rows_per_page', 'timezone', 'roleid'
];
}
else {
$output = array_unique(array_merge(['userid', 'roleid'], $options['selectUsers']));
}
$users = DB::select('users', [
'output' => $output,
'filter' => ['roleid' => $roleids],
'preservekeys' => true
]);
$relation_map = $this->createRelationMap($users, 'roleid', 'userid');
$users = $this->unsetExtraFields($users, ['userid', 'roleid'], $options['selectUsers']);
$result = $relation_map->mapMany($result, $users, 'users');
if ($options['selectUsers'] === API_OUTPUT_COUNT) {
foreach ($result as &$row) {
$row['users'] = (string) count($row['users']);
}
unset($row);
}
}
return $result;
}
/**
* @param array $rules
* @param array $output
* @param int $type
*
* @return array
*/
private function getRelatedUiRules(array $rules, array $output, int $type): array {
$ui_default_access = array_key_exists('ui.default_access', $rules)
? $rules['ui.default_access']
: (string) ZBX_ROLE_RULE_ENABLED;
$result = [];
if (in_array('ui', $output, true)) {
$ui = array_fill_keys(CRoleHelper::getUiElementsByUserType($type), $ui_default_access);
$ui = array_intersect_key($rules, $ui) + $ui;
$result['ui'] = [];
foreach ($ui as $ui_element => $status) {
$result['ui'][] = [
'name' => substr($ui_element, strlen('ui.')),
'status' => $status
];
}
}
if (in_array('ui.default_access', $output, true)) {
$result['ui.default_access'] = $ui_default_access;
}
return $result;
}
/**
* @param array $rules
* @param array $output
*
* @return array
*/
private function getRelatedServicesReadRules(array $rules, array $output): array {
$result = [];
$services_read_mode = array_key_exists('services.read', $rules)
? $rules['services.read']
: (string) ZBX_ROLE_RULE_SERVICES_ACCESS_ALL;
if (in_array('services.read.mode', $output, true)) {
$result['services.read.mode'] = $services_read_mode;
}
if (in_array('services.read.list', $output, true)) {
$result['services.read.list'] = [];
if ($services_read_mode == ZBX_ROLE_RULE_SERVICES_ACCESS_CUSTOM) {
$enum = 'services.read.id.';
foreach ($rules as $rule_name => $rule_value) {
if (strpos($rule_name, $enum) === 0) {
$result['services.read.list'][] = ['serviceid' => $rule_value];
}
}
}
}
if (in_array('services.read.tag', $output, true)) {
$result['services.read.tag'] = ['tag' => '', 'value' => ''];
if ($services_read_mode == ZBX_ROLE_RULE_SERVICES_ACCESS_CUSTOM) {
if (array_key_exists('services.read.tag.name', $rules)) {
$result['services.read.tag']['tag'] = $rules['services.read.tag.name'];
}
if (array_key_exists('services.read.tag.value', $rules)
&& $result['services.read.tag']['tag'] !== '') {
$result['services.read.tag']['value'] = $rules['services.read.tag.value'];
}
}
}
return $result;
}
/**
* @param array $rules
* @param array $output
*
* @return array
*/
private function getRelatedServicesWriteRules(array $rules, array $output): array {
$result = [];
$services_write_mode = array_key_exists('services.write', $rules)
? $rules['services.write']
: (string) ZBX_ROLE_RULE_SERVICES_ACCESS_CUSTOM;
if (in_array('services.write.mode', $output, true)) {
$result['services.write.mode'] = $services_write_mode;
}
if (in_array('services.write.list', $output, true)) {
$result['services.write.list'] = [];
if ($services_write_mode == ZBX_ROLE_RULE_SERVICES_ACCESS_CUSTOM) {
$enum = 'services.write.id.';
foreach ($rules as $rule_name => $rule_value) {
if (strpos($rule_name, $enum) === 0) {
$result['services.write.list'][] = ['serviceid' => $rule_value];
}
}
}
}
if (in_array('services.write.tag', $output, true)) {
$result['services.write.tag'] = ['tag' => '', 'value' => ''];
if ($services_write_mode == ZBX_ROLE_RULE_SERVICES_ACCESS_CUSTOM) {
if (array_key_exists('services.write.tag.name', $rules)) {
$result['services.write.tag']['tag'] = $rules['services.write.tag.name'];
}
if (array_key_exists('services.write.tag.value', $rules)
&& $result['services.write.tag']['tag'] !== '') {
$result['services.write.tag']['value'] = $rules['services.write.tag.value'];
}
}
}
return $result;
}
/**
* @param array $rules
* @param array $output
*
* @return array
*
* @throws APIException
*/
private function getRelatedModulesRules(array $rules, array $output): array {
$modules_default_access = array_key_exists('modules.default_access', $rules)
? $rules['modules.default_access']
: (string) ZBX_ROLE_RULE_ENABLED;
$result = [];
if (in_array('modules', $output, true)) {
$modules = [];
foreach (self::getModuleIds() as $moduleid) {
$modules[$moduleid] = [
'moduleid' => $moduleid,
'status' => $modules_default_access
];
}
$enum = 'modules.module.';
foreach ($rules as $rule_name => $rule_value) {
if (array_key_exists($rule_value, $modules) && strpos($rule_name, $enum) === 0) {
$modules[$rule_value]['status'] = $modules_default_access == ZBX_ROLE_RULE_ENABLED
? (string) ZBX_ROLE_RULE_DISABLED
: (string) ZBX_ROLE_RULE_ENABLED;
}
}
$result['modules'] = array_values($modules);
}
if (in_array('modules.default_access', $output, true)) {
$result['modules.default_access'] = $modules_default_access;
}
return $result;
}
/**
* @param array $rules
* @param array $output
*
* @return array
*/
private function getRelatedApiRules(array $rules, array $output): array {
$result = [];
if (in_array('api.access', $output, true)) {
$result['api.access'] = array_key_exists('api.access', $rules)
? $rules['api.access']
: (string) ZBX_ROLE_RULE_ENABLED;
}
if (in_array('api.mode', $output, true)) {
$result['api.mode'] = array_key_exists('api.mode', $rules)
? $rules['api.mode']
: (string) ZBX_ROLE_RULE_API_MODE_DENY;
}
if (in_array('api', $output, true)) {
$result['api'] = [];
$enum = 'api.method.';
foreach ($rules as $rule_name => $rule_value) {
if (strpos($rule_name, $enum) === 0) {
$result['api'][] = $rule_value;
}
}
}
return $result;
}
/**
* @param array $rules
* @param array $output
* @param int $type
*
* @return array
*/
private function getRelatedActionsRules(array $rules, array $output, int $type): array {
$actions_default_access = array_key_exists('actions.default_access', $rules)
? $rules['actions.default_access']
: (string) ZBX_ROLE_RULE_ENABLED;
$result = [];
if (in_array('actions', $output, true)) {
$actions = array_fill_keys(CRoleHelper::getActionsByUserType($type), $actions_default_access);
$actions = array_intersect_key($rules, $actions) + $actions;
$result['actions'] = [];
foreach ($actions as $action => $status) {
$result['actions'][] = [
'name' => substr($action, strlen('actions.')),
'status' => $status
];
}
}
if (in_array('actions.default_access', $output, true)) {
$result['actions.default_access'] = $actions_default_access;
}
return $result;
}
/**
* @return array
*
* @throws APIException
*/
private static function getModuleIds(): array {
$modules = API::getApiService('module')->get([
'output' => [],
'preservekeys' => true
], false);
return array_keys($modules);
}
}