1<?php
2/*
3** Zabbix
4** Copyright (C) 2001-2021 Zabbix SIA
5**
6** This program is free software; you can redistribute it and/or modify
7** it under the terms of the GNU General Public License as published by
8** the Free Software Foundation; either version 2 of the License, or
9** (at your option) any later version.
10**
11** This program is distributed in the hope that it will be useful,
12** but WITHOUT ANY WARRANTY; without even the implied warranty of
13** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14** GNU General Public License for more details.
15**
16** You should have received a copy of the GNU General Public License
17** along with this program; if not, write to the Free Software
18** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19**/
20
21
22class CAudit {
23
24	/**
25	 * Add simple audit record.
26	 *
27	 * @param string $userid
28	 * @param string $ip
29	 * @param int    $action        AUDIT_ACTION_*
30	 * @param int    $resourcetype  AUDIT_RESOURCE_*
31	 * @param string $details
32	 */
33	static public function addDetails($userid, $ip, $action, $resourcetype, $details = '') {
34		DB::insert('auditlog', [[
35			'userid' => $userid,
36			'clock' => time(),
37			'ip' => substr($ip, 0, 39),
38			'action' => $action,
39			'resourcetype' => $resourcetype,
40			'details' => $details
41		]]);
42	}
43
44	/**
45	 * Add audit records.
46	 *
47	 * @param string $userid
48	 * @param string $ip
49	 * @param int    $action        AUDIT_ACTION_*
50	 * @param int    $resourcetype  AUDIT_RESOURCE_*
51	 * @param array  $objects
52	 * @param array  $objects_old
53	 */
54	static public function addBulk($userid, $ip, $action, $resourcetype, array $objects, array $objects_old = null) {
55		$masked_fields = [
56			'users' => ['passwd' => true]
57		];
58
59		switch ($resourcetype) {
60			case AUDIT_RESOURCE_ACTION:
61				$field_name_resourceid = 'actionid';
62				$field_name_resourcename = 'name';
63				$table_name = 'actions';
64				break;
65
66			case AUDIT_RESOURCE_APPLICATION:
67				$field_name_resourceid = 'applicationid';
68				$field_name_resourcename = 'name';
69				$table_name = 'applications';
70				break;
71
72			case AUDIT_RESOURCE_CORRELATION:
73				$field_name_resourceid = 'correlationid';
74				$field_name_resourcename = 'name';
75				$table_name = 'correlation';
76				break;
77
78			case AUDIT_RESOURCE_DASHBOARD:
79				$field_name_resourceid = 'dashboardid';
80				$field_name_resourcename = 'name';
81				$table_name = 'dashboard';
82				break;
83
84			case AUDIT_RESOURCE_DISCOVERY_RULE:
85				$field_name_resourceid = 'druleid';
86				$field_name_resourcename = 'name';
87				$table_name = 'drules';
88				break;
89
90			case AUDIT_RESOURCE_GRAPH:
91			case AUDIT_RESOURCE_GRAPH_PROTOTYPE:
92				$field_name_resourceid = 'graphid';
93				$field_name_resourcename = 'name';
94				$table_name = 'graphs';
95				break;
96
97			case AUDIT_RESOURCE_HOST_PROTOTYPE:
98				$field_name_resourceid = 'hostid';
99				$field_name_resourcename = 'host';
100				$table_name = 'hosts';
101				break;
102
103			case AUDIT_RESOURCE_HOST_GROUP:
104				$field_name_resourceid = 'groupid';
105				$field_name_resourcename = 'name';
106				$table_name = 'groups';
107				break;
108
109			case AUDIT_RESOURCE_ICON_MAP:
110				$field_name_resourceid = 'iconmapid';
111				$field_name_resourcename = 'name';
112				$table_name = 'icon_map';
113				break;
114
115			case AUDIT_RESOURCE_ITEM:
116			case AUDIT_RESOURCE_ITEM_PROTOTYPE:
117				$field_name_resourceid = 'itemid';
118				$field_name_resourcename = 'name';
119				$table_name = 'items';
120				break;
121
122			case AUDIT_RESOURCE_MACRO:
123				$field_name_resourceid = 'globalmacroid';
124				$field_name_resourcename = 'macro';
125				$table_name = 'globalmacro';
126				break;
127
128			case AUDIT_RESOURCE_MAINTENANCE:
129				$field_name_resourceid = 'maintenanceid';
130				$field_name_resourcename = 'name';
131				$table_name = 'maintenances';
132				break;
133
134			case AUDIT_RESOURCE_PROXY:
135				$field_name_resourceid = 'proxyid';
136				$field_name_resourcename = 'host';
137				$table_name = 'hosts';
138				break;
139
140			case AUDIT_RESOURCE_SCENARIO:
141				$field_name_resourceid = 'httptestid';
142				$field_name_resourcename = 'name';
143				$table_name = 'httptest';
144				break;
145
146			case AUDIT_RESOURCE_SCRIPT:
147				$field_name_resourceid = 'scriptid';
148				$field_name_resourcename = 'name';
149				$table_name = 'scripts';
150				break;
151
152			case AUDIT_RESOURCE_TRIGGER:
153			case AUDIT_RESOURCE_TRIGGER_PROTOTYPE:
154				$field_name_resourceid = 'triggerid';
155				$field_name_resourcename = 'description';
156				$table_name = 'triggers';
157				break;
158
159			case AUDIT_RESOURCE_USER:
160				$field_name_resourceid = 'userid';
161				$field_name_resourcename = 'alias';
162				$table_name = 'users';
163				break;
164
165			case AUDIT_RESOURCE_USER_GROUP:
166				$field_name_resourceid = 'usrgrpid';
167				$field_name_resourcename = 'name';
168				$table_name = 'usrgrp';
169				break;
170
171			case AUDIT_RESOURCE_VALUE_MAP:
172				$field_name_resourceid = 'valuemapid';
173				$field_name_resourcename = 'name';
174				$table_name = 'valuemaps';
175				break;
176
177			case AUDIT_RESOURCE_HOST:
178				$field_name_resourceid = 'hostid';
179				$field_name_resourcename = 'host';
180				$table_name = 'hosts';
181				break;
182
183			case AUDIT_RESOURCE_TEMPLATE:
184				$field_name_resourceid = 'templateid';
185				$field_name_resourcename = 'host';
186				$table_name = 'hosts';
187				break;
188
189			default:
190				return;
191		}
192
193		$clock = time();
194		$ip = substr($ip, 0, 39);
195
196		$auditlog = [];
197		$objects_diff = [];
198
199		foreach ($objects as $object) {
200			$resourceid = $object[$field_name_resourceid];
201
202			if ($action == AUDIT_ACTION_UPDATE) {
203				$object_old = $objects_old[$resourceid];
204
205				/**
206				 * Convert two dimension array to one dimension array,
207				 * because array_diff and array_intersect work only with one dimension array.
208				 */
209				$object_old = array_filter($object_old, function ($val) {
210					return !is_array($val);
211				});
212				$object = array_filter($object, function ($val) {
213					return !is_array($val);
214				});
215
216				$object_diff = array_diff_assoc(array_intersect_key($object_old, $object), $object);
217
218				if (!$object_diff) {
219					continue;
220				}
221
222				foreach ($object_diff as $field_name => &$values) {
223					if (array_key_exists($table_name, $masked_fields)
224							&& array_key_exists($field_name, $masked_fields[$table_name])) {
225						$object_old[$field_name] = '********';
226						$object[$field_name] = '********';
227					}
228
229					$values = [
230						'old' => $object_old[$field_name],
231						'new' => $object[$field_name]
232					];
233
234				}
235				unset($values);
236
237				$objects_diff[] = $object_diff;
238
239				$resourcename = $object_old[$field_name_resourcename];
240			}
241			else {
242				$resourcename = $object[$field_name_resourcename];
243			}
244
245			if (mb_strlen($resourcename) > 255) {
246				$resourcename = mb_substr($resourcename, 0, 252).'...';
247			}
248
249			$auditlog[] = [
250				'userid' => $userid,
251				'clock' => $clock,
252				'ip' => $ip,
253				'action' => $action,
254				'resourcetype' => $resourcetype,
255				'resourceid' => $resourceid,
256				'resourcename' => $resourcename
257			];
258		}
259
260		if ($auditlog) {
261			$auditids = DB::insertBatch('auditlog', $auditlog);
262
263			if ($action == AUDIT_ACTION_UPDATE) {
264				$auditlog_details = [];
265
266				foreach ($objects_diff as $index => $object_diff) {
267					foreach ($object_diff as $field_name => $values) {
268						$auditlog_details[] = [
269							'auditid' => $auditids[$index],
270							'table_name' => $table_name,
271							'field_name' => $field_name,
272							'oldvalue' => $values['old'],
273							'newvalue' => $values['new']
274						];
275					}
276				}
277
278				DB::insertBatch('auditlog_details', $auditlog_details);
279			}
280		}
281	}
282}
283