write audit log call variant which accepts json objects; old/new value logging for...
[public/netxms.git] / src / server / core / tools.cpp
CommitLineData
7cf549ad 1/*
5039dede 2** NetXMS - Network Management System
43b62436 3** Copyright (C) 2003-2016 Victor Kirhenshtein
5039dede
AK
4**
5** This program is free software; you can redistribute it and/or modify
6** it under the terms of the GNU General Public License as published by
7** the Free Software Foundation; either version 2 of the License, or
8** (at your option) any later version.
9**
10** This program is distributed in the hope that it will be useful,
11** but WITHOUT ANY WARRANTY; without even the implied warranty of
12** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13** GNU General Public License for more details.
14**
15** You should have received a copy of the GNU General Public License
16** along with this program; if not, write to the Free Software
17** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18**
19** File: tools.cpp
20**
21**/
22
23#include "nxcore.h"
24
25#ifdef _WIN32
26# include <io.h>
27#else
28# ifdef HAVE_SYS_UTSNAME_H
29# include <sys/utsname.h>
30# endif
31#endif
32
f375019e
VK
33/**
34 * Get system information string
35 */
35f836fe 36void GetSysInfoStr(TCHAR *pszBuffer, int nMaxSize)
5039dede
AK
37{
38#ifdef _WIN32
39 DWORD dwSize;
35f836fe 40 TCHAR computerName[MAX_COMPUTERNAME_LENGTH + 1] = _T("localhost"), osVersion[256] = _T("unknown");
5039dede
AK
41
42 dwSize = MAX_COMPUTERNAME_LENGTH + 1;
43 GetComputerName(computerName, &dwSize);
44
4d0c32f3 45 GetWindowsVersionString(osVersion, 256);
35f836fe 46 _sntprintf(pszBuffer, nMaxSize, _T("%s %s"), computerName, osVersion);
5039dede
AK
47#else
48# ifdef HAVE_SYS_UTSNAME_H
49 struct utsname uName;
50 if (uname(&uName) >= 0)
51 {
dda7c270 52 _sntprintf(pszBuffer, nMaxSize, _T("%hs %hs Release %hs"), uName.nodename, uName.sysname, uName.release);
5039dede
AK
53 }
54 else
55 {
b0823d06 56#if HAVE_POSIX_STRERROR_R
dda7c270 57 _tcserror_r(errno, pszBuffer, nMaxSize);
5039dede 58#else
dda7c270 59 nx_strncpy(pszBuffer, _tcserror(errno), nMaxSize);
5039dede
AK
60#endif
61 }
62# else
dda7c270
VK
63 _tprintf(_T("GetSysInfoStr: code not implemented\n"));
64 _tcscpy(pszBuffer, _T("UNIX"));
5039dede
AK
65# endif // HAVE_SYS_UTSNAME_H
66
67#endif
68}
69
f375019e
VK
70/**
71 * Get hostname for local machine
72 */
f7694811
VK
73TCHAR *GetLocalHostName(TCHAR *buffer, size_t bufSize)
74{
75#ifdef _WIN32
967893bb 76 DWORD dwSize = (UINT32)bufSize;
f7694811
VK
77 GetComputerName(buffer, &dwSize);
78#else
79#ifdef HAVE_SYS_UTSNAME_H
80 struct utsname uName;
81 if (uname(&uName) >= 0)
82 {
dda7c270
VK
83#ifdef UNICODE
84 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, uName.nodename, -1, buffer, bufSize);
85 buffer[bufSize - 1] = 0;
86#else
f7694811 87 nx_strncpy(buffer, uName.nodename, bufSize);
dda7c270 88#endif
f7694811
VK
89 }
90 else
91 {
92 nx_strncpy(buffer, _T("unknown"), bufSize);
93 }
94#else
95 nx_strncpy(buffer, _T("unknown"), bufSize);
96#endif // HAVE_SYS_UTSNAME_H
97#endif // _WIN32
98 return buffer;
99}
100
e95680e5
VK
101/**
102 * Get IP address for local machine
103 */
c30c0c0f 104InetAddress GetLocalIpAddr()
5039dede 105{
c30c0c0f
VK
106 InetAddress addr;
107 InterfaceList *pIfList = GetLocalInterfaceList();
5039dede
AK
108 if (pIfList != NULL)
109 {
5039dede 110 // Find first interface with IP address
c30c0c0f
VK
111 for(int i = 0; i < pIfList->size(); i++)
112 {
113 InterfaceInfo *iface = pIfList->get(i);
114 if (iface->type == IFTYPE_SOFTWARE_LOOPBACK)
115 continue;
116 for(int j = 0; j < iface->ipAddrList.size(); j++)
5039dede 117 {
c30c0c0f
VK
118 const InetAddress& a = iface->ipAddrList.get(j);
119 if (a.isValidUnicast())
120 {
121 addr = a;
122 goto stop;
123 }
5039dede 124 }
c30c0c0f
VK
125 }
126stop:
98762401 127 delete pIfList;
5039dede 128 }
c30c0c0f 129 return addr;
5039dede
AK
130}
131
f375019e
VK
132/**
133 * Execute external command
134 */
35f836fe 135BOOL ExecCommand(TCHAR *pszCommand)
5039dede
AK
136{
137 BOOL bSuccess = TRUE;
138
139#ifdef _WIN32
140 STARTUPINFO si;
141 PROCESS_INFORMATION pi;
142
143 // Fill in process startup info structure
144 memset(&si, 0, sizeof(STARTUPINFO));
145 si.cb = sizeof(STARTUPINFO);
146 si.dwFlags = 0;
147
148 // Create new process
149 if (!CreateProcess(NULL, pszCommand, NULL, NULL, FALSE, CREATE_NO_WINDOW | DETACHED_PROCESS, NULL, NULL, &si, &pi))
150 {
151 nxlog_write(MSG_CREATE_PROCESS_FAILED, EVENTLOG_ERROR_TYPE, "se", pszCommand, GetLastError());
152 bSuccess = FALSE;
153 }
154 else
155 {
156 // Close all handles
157 CloseHandle(pi.hThread);
158 CloseHandle(pi.hProcess);
159 }
160#else
161 bSuccess = FALSE;
162 {
163 int nPid;
164 char *pCmd[128];
6ba36557 165 int nCount = 0;
5039dede
AK
166 char *pTmp;
167 struct stat st;
168 int state = 0;
169
dda7c270
VK
170#ifdef UNICODE
171 pTmp = MBStringFromWideString(pszCommand);
172#else
173 pTmp = strdup(pszCommand);
174#endif
5039dede
AK
175 if (pTmp != NULL)
176 {
177 pCmd[nCount++] = pTmp;
178 int nLen = strlen(pTmp);
179 for (int i = 0; (i < nLen) && (nCount < 127); i++)
180 {
181 switch(pTmp[i])
182 {
183 case ' ':
184 if (state == 0)
185 {
186 pTmp[i] = 0;
187 if (pTmp[i + 1] != 0)
188 {
189 pCmd[nCount++] = pTmp + i + 1;
190 }
191 }
192 break;
193 case '"':
194 state == 0 ? state++ : state--;
195
196 memmove(pTmp + i, pTmp + i + 1, nLen - i);
197 i--;
198 break;
199 case '\\':
200 if (pTmp[i+1] == '"')
201 {
202 memmove(pTmp + i, pTmp + i + 1, nLen - i);
203 }
204 break;
205 default:
206 break;
207 }
208 }
209 pCmd[nCount] = NULL;
210
6bcafa2d 211 if ((stat(pCmd[0], &st) == 0) && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)))
5039dede
AK
212 {
213 switch ((nPid = fork()))
214 {
215 case -1:
216 nxlog_write(MSG_CREATE_PROCESS_FAILED, EVENTLOG_ERROR_TYPE, "se", pszCommand, errno);
217 break;
218 case 0: // child
219 {
220 int sd = open("/dev/null", O_RDWR);
221 if (sd == -1)
222 {
223 sd = open("/dev/null", O_RDONLY);
224 }
225 close(0);
226 close(1);
227 close(2);
228 dup2(sd, 0);
229 dup2(sd, 1);
230 dup2(sd, 2);
231 close(sd);
232 execv(pCmd[0], pCmd);
233 // should not be reached
234 //_exit((errno == EACCES || errno == ENOEXEC) ? 126 : 127);
235 _exit(127);
236 }
237 break;
238 default: // parent
239 bSuccess = TRUE;
240 break;
241 }
242 }
243
244 free(pTmp);
245 }
246 }
247#endif
248
249 return bSuccess;
250}
251
dcc8b1bc
VK
252/**
253 * Send Wake-on-LAN packet (magic packet) to given IP address
254 * with given MAC address inside
255 */
967893bb 256BOOL SendMagicPacket(UINT32 dwIpAddr, BYTE *pbMacAddr, int iNumPackets)
5039dede 257{
fb5723e7 258 BYTE *pCurr, bPacketData[102];
5039dede
AK
259 SOCKET hSocket;
260 struct sockaddr_in addr;
261 BOOL bResult = TRUE;
262 int i;
7cf549ad 263
5039dede 264 // Create data area
fb5723e7 265 memset(bPacketData, 0xFF, 6);
266 for(i = 0, pCurr = bPacketData + 6; i < 16; i++, pCurr += 6)
5039dede
AK
267 memcpy(pCurr, pbMacAddr, 6);
268
269 // Create socket
270 hSocket = socket(AF_INET, SOCK_DGRAM, 0);
4c0c75c7 271 if (hSocket == INVALID_SOCKET)
d907d4ad 272 {
273 DbgPrintf(5, _T("SendMagicPacket: ERROR creating socket: %s."), _tcserror(errno));
5039dede 274 return FALSE;
d907d4ad 275 }
08f16c05 276 SetSocketBroadcast(hSocket);
5039dede
AK
277
278 memset(&addr, 0, sizeof(struct sockaddr_in));
279 addr.sin_family = AF_INET;
280 addr.sin_addr.s_addr = dwIpAddr;
fb5723e7 281 addr.sin_port = htons(53);
5039dede
AK
282
283 // Send requested number of packets
284 for(i = 0; i < iNumPackets; i++)
fb5723e7 285 if (sendto(hSocket, (char *)bPacketData, 102, 0, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0)
d907d4ad 286 {
287 DbgPrintf(5, _T("SendMagicPacket: ERROR sending message: %s."), _tcserror(errno));
5039dede 288 bResult = FALSE;
d907d4ad 289 }
5039dede
AK
290
291 // Cleanup
292 closesocket(hSocket);
293 return bResult;
294}
295
752074c0
VK
296/**
297 * Decode SQL string and set as NXCP variable's value
298 */
b368969c 299void DecodeSQLStringAndSetVariable(NXCPMessage *pMsg, UINT32 dwVarId, TCHAR *pszStr)
5039dede
AK
300{
301 DecodeSQLString(pszStr);
b368969c 302 pMsg->setField(dwVarId, pszStr);
5039dede
AK
303}
304
752074c0
VK
305/**
306 * Escape string
307 */
5039dede
AK
308void EscapeString(String &str)
309{
ce7565e7
VK
310 str.escapeCharacter(_T('\\'), _T('\\'));
311 str.escapeCharacter(_T('"'), _T('\\'));
6bcafa2d
VK
312 str.replace(_T("\b"), _T("\\b"));
313 str.replace(_T("\r"), _T("\\r"));
314 str.replace(_T("\n"), _T("\\n"));
315 str.replace(_T("\t"), _T("\\t"));
5039dede 316}
ba89fed2 317
dcc8b1bc
VK
318/**
319 * Prepare and execute SQL query with single binding - object ID.
320 */
321bool NXCORE_EXPORTABLE ExecuteQueryOnObject(DB_HANDLE hdb, UINT32 objectId, const TCHAR *query)
322{
323 DB_STATEMENT hStmt = DBPrepare(hdb, query);
324 if (hStmt == NULL)
325 return false;
326 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, objectId);
327 bool success = DBExecute(hStmt) ? true : false;
328 DBFreeStatement(hStmt);
329 return success;
330}
b4cf3199
VK
331
332/**
333 * Resolve host name using zone if needed
334 */
335InetAddress NXCORE_EXPORTABLE ResolveHostName(UINT32 zoneId, const TCHAR *hostname)
336{
337 InetAddress ipAddr = InetAddress::parse(hostname);
338 if (!ipAddr.isValid() && IsZoningEnabled() && (zoneId != 0))
339 {
340 // resolve address through proxy agent
341 Zone *zone = FindZoneByGUID(zoneId);
342 if (zone != NULL)
343 {
43b62436 344 Node *proxy = (Node *)FindObjectById(zone->getProxyNodeId(), OBJECT_NODE);
b4cf3199
VK
345 if (proxy != NULL)
346 {
347 TCHAR query[256], buffer[128];
348 _sntprintf(query, 256, _T("Net.Resolver.AddressByName(%s)"), hostname);
349 if (proxy->getItemFromAgent(query, 128, buffer) == ERR_SUCCESS)
350 {
351 ipAddr = InetAddress::parse(buffer);
352 }
353 }
354 }
355 }
356
357 // Resolve address through local resolver
358 if (!ipAddr.isValid())
359 {
360 ipAddr = InetAddress::resolveHostName(hostname);
361 }
362 return ipAddr;
363}
d1c4701c
VK
364
365/**
366 * Create object URL from NXCP message
367 */
368ObjectUrl::ObjectUrl(NXCPMessage *msg, UINT32 baseId)
369{
370 m_id = msg->getFieldAsUInt32(baseId);
371 m_url = msg->getFieldAsString(baseId + 1);
372 m_description = msg->getFieldAsString(baseId + 2);
373}
374
375/**
376 * Create object URL from database result set
377 */
378ObjectUrl::ObjectUrl(DB_RESULT hResult, int row)
379{
380 m_id = DBGetFieldULong(hResult, row, 0);
381 m_url = DBGetField(hResult, row, 1, NULL, 0);
382 m_description = DBGetField(hResult, row, 2, NULL, 0);
383}
384
385/**
386 * Object URL destructor
387 */
388ObjectUrl::~ObjectUrl()
389{
390 free(m_url);
391 free(m_description);
392}
393
394/**
395 * Fill NXCP message
396 */
397void ObjectUrl::fillMessage(NXCPMessage *msg, UINT32 baseId)
398{
399 msg->setField(baseId, m_id);
400 msg->setField(baseId + 1, m_url);
401 msg->setField(baseId + 2, m_description);
402}
379f8228 403
404/**
405 * Distance array sorting callback
406 */
407int DistanceSortCallback(const void *obj1, const void *obj2)
408{
409 return ((ObjectsDistance *)obj1)->m_distance - ((ObjectsDistance *)obj2)->m_distance;
410}
411
412/**
413 * Calculate nearest objects from current one
414 * Object ref count will be automatically decreased on array delete
415 */
416ObjectArray<ObjectsDistance> *FindNearestObjects(UINT32 currObjectId, int maxDistance, bool (* filter)(NetObj *object, void *data), void *sortData, int (* calculateRealDistance)(GeoLocation &loc1, GeoLocation &loc2))
417{
418 NetObj *currObj = FindObjectById(currObjectId);
419 currObj->incRefCount();
420 GeoLocation currLocation = currObj->getGeoLocation();
3e7ea9a9 421 if (currLocation.getType() == GL_UNSET)
379f8228 422 {
423 currObj->decRefCount();
424 return NULL;
425 }
426
427 ObjectArray<NetObj> *objects = g_idxObjectById.getObjects(true, filter, sortData);
428 ObjectArray<ObjectsDistance> *result = new ObjectArray<ObjectsDistance>(16, 16, true);
429 for(int i = 0; i < objects->size(); i++)
430 {
431 NetObj *object = objects->get(i);
432 GeoLocation location = object->getGeoLocation();
3e7ea9a9 433 if (currLocation.getType() == GL_UNSET)
379f8228 434 {
435 object->decRefCount();
436 continue;
437 }
438
3e7ea9a9 439 // leave object only in given distance
379f8228 440 int distance = currLocation.calculateDistance(location);
3e7ea9a9 441 if (distance > maxDistance)
379f8228 442 {
443 object->decRefCount();
444 continue;
445 }
446
3e7ea9a9
VK
447 // remove current object from list
448 if (object->getId() == currObjectId)
379f8228 449 {
450 object->decRefCount();
451 continue;
452 }
453
3e7ea9a9
VK
454 // Filter objects by real path calculation
455 if (calculateRealDistance != NULL)
379f8228 456 {
457 distance = calculateRealDistance(location, currLocation);
458 if(distance > maxDistance)
459 {
460 object->decRefCount();
461 continue;
462 }
463 }
464
465 result->add(new ObjectsDistance(object, distance));
466 }
467
3e7ea9a9 468 // Sort filtered objects
379f8228 469 result->sort(DistanceSortCallback);
470
471 currObj->decRefCount();
472 return result;
473}
0d402aa8
VK
474
475/**
476 * Create JSON string from wide character string
477 */
478json_t *json_string_w(const WCHAR *s)
479{
480 char *us = UTF8StringFromWideString(s);
481 json_t *js = json_string(us);
482 free(us);
483 return js;
484}