fixed memory leak
[public/netxms.git] / src / server / core / session.cpp
CommitLineData
7a4c94ee 1/*
5039dede 2** NetXMS - Network Management System
69e8229d 3** Copyright (C) 2003-2017 Raden Solutions
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: session.cpp
20**
21**/
22
23#include "nxcore.h"
fdbee7f8 24#include <netxms_mt.h>
bf6fb6c3 25#include <nxtools.h>
9ece2b31 26#include <nxstat.h>
5039dede
AK
27
28#ifdef _WIN32
29#include <psapi.h>
30#else
31#include <dirent.h>
32#endif
33
4ef60905
AK
34#ifdef WITH_ZMQ
35#include "zeromq.h"
36#endif
37
5039dede
AK
38#ifndef min
39#define min(a,b) ((a) < (b) ? (a) : (b))
40#endif
41
c733fcc4 42// WARNING! this hack works only for d2i_X509(); be careful when adding new code
5039dede
AK
43#ifdef OPENSSL_CONST
44# undef OPENSSL_CONST
45#endif
46#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
47# define OPENSSL_CONST const
48#else
49# define OPENSSL_CONST
50#endif
51
534e1b83
VK
52/**
53 * Constants
54 */
5039dede
AK
55#define TRAP_CREATE 1
56#define TRAP_UPDATE 2
57#define TRAP_DELETE 3
58
b9b2b87b 59#define MAX_MSG_SIZE 4194304
5039dede 60
534e1b83
VK
61/**
62 * Externals
63 */
5039dede 64extern Queue g_nodePollerQueue;
d140955e
VK
65extern Queue g_dataCollectionQueue;
66extern Queue g_dciCacheLoaderQueue;
5039dede 67
2a964810 68void UnregisterClientSession(int id);
b9b2b87b 69void ResetDiscoveryPoller();
b368969c 70NXCPMessage *ForwardMessageToReportingServer(NXCPMessage *request, ClientSession *session);
bc7767c4 71void RemovePendingFileTransferRequests(ClientSession *session);
ba889094 72bool UpdateAddressListFromMessage(NXCPMessage *msg);
4fd0b7ca 73void FillComponentsMessage(NXCPMessage *msg);
c733fcc4 74
0cf6fcbd
VK
75void GetPredictionEngines(NXCPMessage *msg);
76bool GetPredictedData(ClientSession *session, const NXCPMessage *request, NXCPMessage *response, DataCollectionTarget *dcTarget);
5039dede 77
3c463101 78void GetAgentTunnels(NXCPMessage *msg);
c733fcc4
VK
79UINT32 BindAgentTunnel(UINT32 tunnelId, UINT32 nodeId);
80UINT32 UnbindAgentTunnel(UINT32 nodeId);
81
82
534e1b83
VK
83/**
84 * Node poller start data
85 */
5039dede
AK
86typedef struct
87{
88 ClientSession *pSession;
89 Node *pNode;
90 int iPollType;
967893bb 91 UINT32 dwRqId;
5039dede
AK
92} POLLER_START_DATA;
93
534e1b83
VK
94/**
95 * Additional processing thread start data
96 */
5039dede
AK
97typedef struct
98{
99 ClientSession *pSession;
b368969c 100 NXCPMessage *pMsg;
5039dede
AK
101} PROCTHREAD_START_DATA;
102
7cf549ad 103/**
c044d4f3 104 * Callback to delete agent connections for loading files in destructor
7cf549ad 105 */
106static void DeleteCallback(NetObj* obj, void *data)
107{
7dd6369a 108 ((AgentConnection *)obj)->decRefCount();
7cf549ad 109}
110
8581943e
VK
111/**
112 * Callback for sending image library delete notifications
113 */
114static void ImageLibraryDeleteCallback(ClientSession *pSession, void *pArg)
115{
b8b6cd2f 116 pSession->onLibraryImageChange(*((const uuid *)pArg), true);
8581943e
VK
117}
118
534e1b83
VK
119/**
120 * Additional message processing thread starters
121 */
5039dede
AK
122#define CALL_IN_NEW_THREAD(func, msg) \
123{ \
124 PROCTHREAD_START_DATA *pData = (PROCTHREAD_START_DATA *)malloc(sizeof(PROCTHREAD_START_DATA)); \
125 pData->pSession = this; \
126 pData->pMsg = msg; \
127 msg = NULL; /* prevent deletion by main processing thread*/ \
c044d4f3 128 InterlockedIncrement(&m_refCount); \
134c3d00 129 ThreadPoolExecute(g_mainThreadPool, ThreadStarter_##func, pData); \
5039dede
AK
130}
131
132#define DEFINE_THREAD_STARTER(func) \
134c3d00 133void ClientSession::ThreadStarter_##func(void *pArg) \
5039dede 134{ \
43750f03 135 ((PROCTHREAD_START_DATA *)pArg)->pSession->debugPrintf(6, _T("Method ") _T(#func) _T(" called on background thread")); \
5039dede 136 ((PROCTHREAD_START_DATA *)pArg)->pSession->func(((PROCTHREAD_START_DATA *)pArg)->pMsg); \
c044d4f3 137 InterlockedDecrement(&((PROCTHREAD_START_DATA *)pArg)->pSession->m_refCount); \
5039dede
AK
138 delete ((PROCTHREAD_START_DATA *)pArg)->pMsg; \
139 free(pArg); \
5039dede
AK
140}
141
78ccd7b4 142DEFINE_THREAD_STARTER(cancelFileMonitoring)
92c51b1d 143DEFINE_THREAD_STARTER(clearDCIData)
1da08bc6 144DEFINE_THREAD_STARTER(createObject)
e31c8e60 145DEFINE_THREAD_STARTER(executeAction)
78ccd7b4 146DEFINE_THREAD_STARTER(executeScript)
e9bf9011 147DEFINE_THREAD_STARTER(executeLibraryScript)
78ccd7b4 148DEFINE_THREAD_STARTER(fileManagerControl)
80e0db05 149DEFINE_THREAD_STARTER(findIpAddress)
78ccd7b4 150DEFINE_THREAD_STARTER(findMacAddress)
f1984eb9 151DEFINE_THREAD_STARTER(findHostname)
78ccd7b4
VK
152DEFINE_THREAD_STARTER(findNodeConnection)
153DEFINE_THREAD_STARTER(forceDCIPoll)
154DEFINE_THREAD_STARTER(forwardToReportingServer)
155DEFINE_THREAD_STARTER(getAgentFile)
3ddc492b 156DEFINE_THREAD_STARTER(getAlarms)
2bac37f9 157DEFINE_THREAD_STARTER(getAlarmEvents)
78ccd7b4
VK
158DEFINE_THREAD_STARTER(getCollectedData)
159DEFINE_THREAD_STARTER(getLocationHistory)
160DEFINE_THREAD_STARTER(getNetworkPath)
0cf6fcbd 161DEFINE_THREAD_STARTER(getPredictedData)
78ccd7b4
VK
162DEFINE_THREAD_STARTER(getRoutingTable)
163DEFINE_THREAD_STARTER(getServerFile)
164DEFINE_THREAD_STARTER(getServerLogQueryData)
165DEFINE_THREAD_STARTER(getSwitchForwardingDatabase)
166DEFINE_THREAD_STARTER(getTableCollectedData)
167DEFINE_THREAD_STARTER(importConfiguration)
3c35018e 168DEFINE_THREAD_STARTER(openHelpdeskIssue)
78ccd7b4
VK
169DEFINE_THREAD_STARTER(processConsoleCommand)
170DEFINE_THREAD_STARTER(queryAgentTable)
171DEFINE_THREAD_STARTER(queryL2Topology)
172DEFINE_THREAD_STARTER(queryParameter)
173DEFINE_THREAD_STARTER(queryServerLog)
78ccd7b4 174DEFINE_THREAD_STARTER(sendMib)
7cf549ad 175DEFINE_THREAD_STARTER(uploadUserFileToAgent)
badd6e08
VK
176DEFINE_THREAD_STARTER(getRepositories)
177DEFINE_THREAD_STARTER(addRepository)
178DEFINE_THREAD_STARTER(modifyRepository)
179DEFINE_THREAD_STARTER(deleteRepository)
5039dede 180
534e1b83
VK
181/**
182 * Client communication read thread starter
183 */
184THREAD_RESULT THREAD_CALL ClientSession::readThreadStarter(void *pArg)
5039dede 185{
62768df3 186 ((ClientSession *)pArg)->readThread();
5039dede
AK
187
188 // When ClientSession::ReadThread exits, all other session
189 // threads are already stopped, so we can safely destroy
190 // session object
2a964810 191 UnregisterClientSession(((ClientSession *)pArg)->getId());
5039dede
AK
192 delete (ClientSession *)pArg;
193 return THREAD_OK;
194}
195
134c3d00 196 /**
534e1b83
VK
197 * Client communication write thread starter
198 */
199THREAD_RESULT THREAD_CALL ClientSession::writeThreadStarter(void *pArg)
5039dede 200{
62768df3 201 ((ClientSession *)pArg)->writeThread();
5039dede
AK
202 return THREAD_OK;
203}
204
534e1b83
VK
205/**
206 * Received message processing thread starter
207 */
208THREAD_RESULT THREAD_CALL ClientSession::processingThreadStarter(void *pArg)
5039dede 209{
62768df3 210 ((ClientSession *)pArg)->processingThread();
5039dede
AK
211 return THREAD_OK;
212}
213
534e1b83
VK
214/**
215 * Client session class constructor
216 */
69e8229d 217ClientSession::ClientSession(SOCKET hSocket, struct sockaddr *addr)
5039dede 218{
b784f8ac
VK
219 m_sendQueue = new Queue;
220 m_requestQueue = new Queue;
5039dede 221 m_hSocket = hSocket;
2a964810
VK
222 m_id = -1;
223 m_state = SESSION_STATE_INIT;
5039dede
AK
224 m_pCtx = NULL;
225 m_hWriteThread = INVALID_THREAD_HANDLE;
226 m_hProcessingThread = INVALID_THREAD_HANDLE;
d3a7cf4c 227 m_mutexSocketWrite = MutexCreate();
5039dede
AK
228 m_mutexSendObjects = MutexCreate();
229 m_mutexSendAlarms = MutexCreate();
230 m_mutexSendActions = MutexCreate();
231 m_mutexSendAuditLog = MutexCreate();
5039dede 232 m_mutexPollerInit = MutexCreate();
c044d4f3 233 m_subscriptionLock = MutexCreate();
84ea7692 234 m_subscriptions = new StringObjectMap<UINT32>(true);
5039dede 235 m_dwFlags = 0;
f8c6f10f 236 m_clientType = CLIENT_TYPE_DESKTOP;
60557d06
VK
237 m_clientAddr = (struct sockaddr *)nx_memdup(addr, (addr->sa_family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6));
238 if (addr->sa_family == AF_INET)
91f6b72c 239 IpToStr(ntohl(((struct sockaddr_in *)m_clientAddr)->sin_addr.s_addr), m_workstation);
60557d06
VK
240#ifdef WITH_IPV6
241 else
91f6b72c 242 Ip6ToStr(((struct sockaddr_in6 *)m_clientAddr)->sin6_addr.s6_addr, m_workstation);
60557d06 243#endif
91f6b72c 244 m_webServerAddress[0] = 0;
77a08c86
VK
245 m_loginName[0] = 0;
246 _tcscpy(m_sessionName, _T("<not logged in>"));
247 _tcscpy(m_clientInfo, _T("n/a"));
5039dede 248 m_dwUserId = INVALID_INDEX;
c044d4f3 249 m_dwSystemAccess = 0;
5039dede
AK
250 m_dwOpenDCIListSize = 0;
251 m_pOpenDCIList = NULL;
252 m_ppEPPRuleList = NULL;
c044d4f3 253 m_wCurrentCmd = 0;
c044d4f3
VK
254 m_dwNumRecordsToUpload = 0;
255 m_dwRecordsUploaded = 0;
256 m_refCount = 0;
5039dede 257 m_dwEncryptionRqId = 0;
c044d4f3 258 m_dwEncryptionResult = 0;
5039dede 259 m_condEncryptionSetup = INVALID_CONDITION_HANDLE;
200d662d 260 m_console = NULL;
a51628e2 261 m_loginTime = time(NULL);
33dfe57e 262 m_musicTypeList.add(_T("wav"));
2a964810 263 _tcscpy(m_language, _T("en"));
45ac5dd0 264 m_serverCommands = new HashMap<UINT32, CommandExec>(true);
b8b6cd2f 265 m_downloadFileMap = new HashMap<UINT32, ServerDownloadFileInfo>(true);
5039dede
AK
266}
267
534e1b83
VK
268/**
269 * Destructor
270 */
5039dede
AK
271ClientSession::~ClientSession()
272{
273 if (m_hSocket != -1)
274 closesocket(m_hSocket);
b784f8ac
VK
275 delete m_sendQueue;
276 delete m_requestQueue;
2de8de66 277 free(m_clientAddr);
d3a7cf4c 278 MutexDestroy(m_mutexSocketWrite);
5039dede
AK
279 MutexDestroy(m_mutexSendObjects);
280 MutexDestroy(m_mutexSendAlarms);
281 MutexDestroy(m_mutexSendActions);
282 MutexDestroy(m_mutexSendAuditLog);
5039dede 283 MutexDestroy(m_mutexPollerInit);
c044d4f3 284 MutexDestroy(m_subscriptionLock);
84ea7692
VK
285 delete m_subscriptions;
286 free(m_pOpenDCIList);
5039dede
AK
287 if (m_ppEPPRuleList != NULL)
288 {
967893bb 289 UINT32 i;
5039dede
AK
290
291 if (m_dwFlags & CSF_EPP_UPLOAD) // Aborted in the middle of EPP transfer
292 for(i = 0; i < m_dwRecordsUploaded; i++)
293 delete m_ppEPPRuleList[i];
294 free(m_ppEPPRuleList);
295 }
98abc9f1
VK
296 if (m_pCtx != NULL)
297 m_pCtx->decRefCount();
5039dede
AK
298 if (m_condEncryptionSetup != INVALID_CONDITION_HANDLE)
299 ConditionDestroy(m_condEncryptionSetup);
7a4c94ee 300
200d662d
VK
301 if (m_console != NULL)
302 {
303 delete m_console->pMsg;
304 free(m_console);
305 }
810bd8c4 306 m_musicTypeList.clear();
a6312bd6 307 if (m_agentConn.size() > 0)
7cf549ad 308 {
309 m_agentConn.forEach(&DeleteCallback, NULL);
310 }
45ac5dd0
EJ
311
312 delete m_serverCommands;
69e8229d 313 delete m_downloadFileMap;
5039dede
AK
314}
315
534e1b83
VK
316/**
317 * Start all threads
318 */
200d662d 319void ClientSession::run()
5039dede 320{
534e1b83
VK
321 m_hWriteThread = ThreadCreateEx(writeThreadStarter, 0, this);
322 m_hProcessingThread = ThreadCreateEx(processingThreadStarter, 0, this);
534e1b83 323 ThreadCreate(readThreadStarter, 0, this);
5039dede
AK
324}
325
534e1b83
VK
326/**
327 * Print debug information
328 */
329void ClientSession::debugPrintf(int level, const TCHAR *format, ...)
5039dede 330{
2df047f4 331 if (level <= nxlog_get_debug_level())
5039dede
AK
332 {
333 va_list args;
6be0a20b 334 TCHAR buffer[8192];
5039dede
AK
335
336 va_start(args, format);
6be0a20b 337 _vsntprintf(buffer, 8192, format, args);
5039dede 338 va_end(args);
2a964810 339 DbgPrintf(level, _T("[CLSN-%d] %s"), m_id, buffer);
5039dede
AK
340 }
341}
342
badd6e08
VK
343/**
344 * Write audit log
345 */
346void ClientSession::writeAuditLog(const TCHAR *subsys, bool success, UINT32 objectId, const TCHAR *format, ...)
347{
348 va_list args;
349 va_start(args, format);
350 WriteAuditLog2(subsys, success, m_dwUserId, m_workstation, m_id, objectId, format, args);
351 va_end(args);
352}
353
dbb49f94
VK
354/**
355 * Write audit log with old and new values for changed entity
356 */
357void ClientSession::writeAuditLogWithValues(const TCHAR *subsys, bool success, UINT32 objectId, const TCHAR *oldValue, const TCHAR *newValue, const TCHAR *format, ...)
358{
359 va_list args;
360 va_start(args, format);
361 WriteAuditLogWithValues2(subsys, success, m_dwUserId, m_workstation, m_id, objectId, oldValue, newValue, format, args);
362 va_end(args);
363}
364
0d402aa8
VK
365/**
366 * Write audit log with old and new values for changed entity
367 */
368void ClientSession::writeAuditLogWithValues(const TCHAR *subsys, bool success, UINT32 objectId, json_t *oldValue, json_t *newValue, const TCHAR *format, ...)
369{
370 va_list args;
371 va_start(args, format);
372 WriteAuditLogWithJsonValues2(subsys, success, m_dwUserId, m_workstation, m_id, objectId, oldValue, newValue, format, args);
373 va_end(args);
374}
375
c044d4f3
VK
376/**
377 * Check channel subscription
378 */
379bool ClientSession::isSubscribedTo(const TCHAR *channel) const
380{
381 MutexLock(m_subscriptionLock);
84ea7692 382 bool subscribed = m_subscriptions->contains(channel);
c044d4f3
VK
383 MutexUnlock(m_subscriptionLock);
384 return subscribed;
385}
386
534e1b83
VK
387/**
388 * Read thread
389 */
62768df3 390void ClientSession::readThread()
5039dede 391{
5039dede 392 TCHAR szBuffer[256];
967893bb 393 UINT32 i;
fffcff95 394 NetObj *object;
5039dede 395
6be0a20b
VK
396 SocketMessageReceiver receiver(m_hSocket, 4096, MAX_MSG_SIZE);
397 while(true)
5039dede 398 {
6be0a20b 399 MessageReceiverResult result;
b368969c 400 NXCPMessage *msg = receiver.readMessage(900000, &result);
5039dede
AK
401
402 // Check for decryption error
6be0a20b 403 if (result == MSGRECV_DECRYPTION_FAILURE)
5039dede 404 {
bf6fb6c3 405 debugPrintf(4, _T("readThread: Unable to decrypt received message"));
5039dede
AK
406 continue;
407 }
408
b368969c 409 // Receive error
6be0a20b 410 if (msg == NULL)
5039dede 411 {
578958a5
VK
412 if (result == MSGRECV_CLOSED)
413 debugPrintf(5, _T("readThread: connection closed"));
414 else
415 debugPrintf(5, _T("readThread: message receiving error (%s)"), AbstractMessageReceiver::resultToText(result));
6be0a20b 416 break;
5039dede
AK
417 }
418
2df047f4 419 if (nxlog_get_debug_level() >= 8)
934f53da 420 {
b368969c 421 String msgDump = NXCPMessage::dump(receiver.getRawMessageBuffer(), NXCP_VERSION);
934f53da
VK
422 debugPrintf(8, _T("Message dump:\n%s"), (const TCHAR *)msgDump);
423 }
424
5039dede 425 // Special handling for raw messages
6be0a20b 426 if (msg->isBinary())
5039dede 427 {
b368969c 428 debugPrintf(6, _T("Received raw message %s"), NXCPMessageCodeName(msg->getCode(), szBuffer));
6be0a20b 429
b368969c
VK
430 if ((msg->getCode() == CMD_FILE_DATA) ||
431 (msg->getCode() == CMD_ABORT_FILE_TRANSFER))
5039dede 432 {
b8b6cd2f 433 ServerDownloadFileInfo *dInfo = m_downloadFileMap->get(msg->getId());
7b45b90d 434 if (dInfo != NULL)
5039dede 435 {
b368969c 436 if (msg->getCode() == CMD_FILE_DATA)
5039dede 437 {
b8b6cd2f 438 if (dInfo->write(msg->getBinaryData(), msg->getBinaryDataSize(), msg->isCompressedStream()))
5039dede 439 {
6be0a20b 440 if (msg->isEndOfFile())
5039dede 441 {
534e1b83 442 debugPrintf(6, _T("Got end of file marker"));
b368969c 443 NXCPMessage response;
5039dede 444
b368969c
VK
445 response.setCode(CMD_REQUEST_COMPLETED);
446 response.setId(msg->getId());
447 response.setField(VID_RCC, RCC_SUCCESS);
6be0a20b 448 sendMessage(&response);
5039dede 449
7b45b90d 450 dInfo->close(true);
69e8229d 451 m_downloadFileMap->remove(msg->getId());
5039dede
AK
452 }
453 }
454 else
455 {
534e1b83 456 debugPrintf(6, _T("I/O error"));
5039dede 457 // I/O error
b368969c 458 NXCPMessage response;
5039dede 459
b368969c
VK
460 response.setCode(CMD_REQUEST_COMPLETED);
461 response.setId(msg->getId());
462 response.setField(VID_RCC, RCC_IO_ERROR);
6be0a20b 463 sendMessage(&response);
5039dede 464
7b45b90d 465 dInfo->close(false);
69e8229d 466 m_downloadFileMap->remove(msg->getId());
5039dede
AK
467 }
468 }
469 else
470 {
471 // Abort current file transfer because of client's problem
7b45b90d 472 dInfo->close(false);
69e8229d 473 m_downloadFileMap->remove(msg->getId());
5039dede
AK
474 }
475 }
476 else
477 {
b368969c 478 AgentConnection *conn = (AgentConnection *)m_agentConn.get(msg->getId());
6be0a20b 479 if (conn != NULL)
7cf549ad 480 {
b368969c 481 if (msg->getCode() == CMD_FILE_DATA)
7cf549ad 482 {
6be0a20b 483 if (conn->sendMessage(msg)) //send raw message
7cf549ad 484 {
6be0a20b 485 if (msg->isEndOfFile())
7cf549ad 486 {
487 debugPrintf(6, _T("Got end of file marker"));
488 //get response with specific ID if ok< then send ok, else send error
b368969c 489 m_agentConn.remove(msg->getId());
7dd6369a 490 conn->decRefCount();
7cf549ad 491
b368969c
VK
492 NXCPMessage response;
493 response.setCode(CMD_REQUEST_COMPLETED);
494 response.setId(msg->getId());
495 response.setField(VID_RCC, RCC_SUCCESS);
6be0a20b 496 sendMessage(&response);
7cf549ad 497 }
498 }
499 else
500 {
501 debugPrintf(6, _T("Error while sending to agent"));
502 // I/O error
b368969c 503 m_agentConn.remove(msg->getId());
7dd6369a 504 conn->decRefCount();
7cf549ad 505
b368969c
VK
506 NXCPMessage response;
507 response.setCode(CMD_REQUEST_COMPLETED);
508 response.setId(msg->getId());
509 response.setField(VID_RCC, RCC_IO_ERROR); //set result that came from agent
6be0a20b 510 sendMessage(&response);
7cf549ad 511 }
512 }
513 else
514 {
515 // Resend abort message
6be0a20b 516 conn->sendMessage(msg);
b368969c 517 m_agentConn.remove(msg->getId());
7dd6369a 518 conn->decRefCount();
7cf549ad 519 }
520 }
521 else
522 {
b368969c 523 debugPrintf(4, _T("Out of state message (ID: %d)"), msg->getId());
7cf549ad 524 }
5039dede
AK
525 }
526 }
6be0a20b 527 delete msg;
5039dede
AK
528 }
529 else
530 {
b368969c 531 if ((msg->getCode() == CMD_SESSION_KEY) && (msg->getId() == m_dwEncryptionRqId))
5039dede 532 {
b368969c 533 debugPrintf(6, _T("Received message %s"), NXCPMessageCodeName(msg->getCode(), szBuffer));
6be0a20b
VK
534 m_dwEncryptionResult = SetupEncryptionContext(msg, &m_pCtx, NULL, g_pServerKey, NXCP_VERSION);
535 receiver.setEncryptionContext(m_pCtx);
5039dede
AK
536 ConditionSet(m_condEncryptionSetup);
537 m_dwEncryptionRqId = 0;
6be0a20b 538 delete msg;
5039dede 539 }
b368969c 540 else if (msg->getCode() == CMD_KEEPALIVE)
5039dede 541 {
b368969c
VK
542 debugPrintf(6, _T("Received message %s"), NXCPMessageCodeName(msg->getCode(), szBuffer));
543 respondToKeepalive(msg->getId());
6be0a20b 544 delete msg;
5039dede
AK
545 }
546 else
547 {
b784f8ac 548 m_requestQueue->put(msg);
5039dede
AK
549 }
550 }
551 }
5039dede 552
134c3d00
VK
553 // Mark as terminated (sendMessage calls will not work after that point)
554 m_dwFlags |= CSF_TERMINATED;
555
5039dede 556 // Notify other threads to exit
b368969c 557 NXCP_MESSAGE *rawMsg;
b784f8ac 558 while((rawMsg = (NXCP_MESSAGE *)m_sendQueue->get()) != NULL)
134c3d00 559 free(rawMsg);
b784f8ac 560 m_sendQueue->put(INVALID_POINTER_VALUE);
6be0a20b 561
b368969c 562 NXCPMessage *msg;
b784f8ac 563 while((msg = (NXCPMessage *)m_requestQueue->get()) != NULL)
6be0a20b 564 delete msg;
b784f8ac 565 m_requestQueue->put(INVALID_POINTER_VALUE);
5039dede
AK
566
567 // Wait for other threads to finish
568 ThreadJoin(m_hWriteThread);
569 ThreadJoin(m_hProcessingThread);
5039dede 570
bc7767c4
VK
571 // remove all pending file transfers from reporting server
572 RemovePendingFileTransferRequests(this);
573
5039dede 574 // Remove all locks created by this session
2a964810 575 RemoveAllSessionLocks(m_id);
5039dede
AK
576 for(i = 0; i < m_dwOpenDCIListSize; i++)
577 {
fffcff95
VK
578 object = FindObjectById(m_pOpenDCIList[i]);
579 if (object != NULL)
46e2b370 580 if (object->isDataCollectionTarget() || (object->getObjectClass() == OBJECT_TEMPLATE))
2a964810 581 ((Template *)object)->unlockDCIList(m_id);
5039dede
AK
582 }
583
584 // Waiting while reference count becomes 0
c044d4f3 585 if (m_refCount > 0)
5039dede 586 {
534e1b83 587 debugPrintf(3, _T("Waiting for pending requests..."));
5039dede
AK
588 do
589 {
590 ThreadSleep(1);
c044d4f3 591 } while(m_refCount > 0);
5039dede
AK
592 }
593
a77272b7
VK
594 if (m_dwFlags & CSF_AUTHENTICATED)
595 {
a0efa7b5 596 CALL_ALL_MODULES(pfClientSessionClose, (this));
77a08c86 597 WriteAuditLog(AUDIT_SECURITY, TRUE, m_dwUserId, m_workstation, m_id, 0, _T("User logged out (client: %s)"), m_clientInfo);
a77272b7 598 }
534e1b83 599 debugPrintf(3, _T("Session closed"));
5039dede
AK
600}
601
534e1b83
VK
602/**
603 * Network write thread
604 */
62768df3 605void ClientSession::writeThread()
5039dede 606{
6be0a20b 607 while(true)
5039dede 608 {
b784f8ac 609 NXCP_MESSAGE *rawMsg = (NXCP_MESSAGE *)m_sendQueue->getOrBlock();
6be0a20b 610 if (rawMsg == INVALID_POINTER_VALUE) // Session termination indicator
5039dede
AK
611 break;
612
134c3d00 613 sendRawMessage(rawMsg);
6be0a20b 614 free(rawMsg);
5039dede
AK
615 }
616}
617
534e1b83
VK
618/**
619 * Message processing thread
620 */
62768df3 621void ClientSession::processingThread()
5039dede 622{
b368969c 623 NXCPMessage *pMsg;
35f836fe 624 TCHAR szBuffer[128];
967893bb 625 UINT32 i;
5039dede
AK
626 int status;
627
4970ef34 628 while(true)
5039dede 629 {
b784f8ac 630 pMsg = (NXCPMessage *)m_requestQueue->getOrBlock();
5039dede
AK
631 if (pMsg == INVALID_POINTER_VALUE) // Session termination indicator
632 break;
633
b368969c 634 m_wCurrentCmd = pMsg->getCode();
534e1b83 635 debugPrintf(6, _T("Received message %s"), NXCPMessageCodeName(m_wCurrentCmd, szBuffer));
7a4c94ee 636 if (!(m_dwFlags & CSF_AUTHENTICATED) &&
637 (m_wCurrentCmd != CMD_LOGIN) &&
5039dede
AK
638 (m_wCurrentCmd != CMD_GET_SERVER_INFO) &&
639 (m_wCurrentCmd != CMD_REQUEST_ENCRYPTION) &&
a854d114
VK
640 (m_wCurrentCmd != CMD_GET_MY_CONFIG) &&
641 (m_wCurrentCmd != CMD_REGISTER_AGENT))
5039dede
AK
642 {
643 delete pMsg;
644 continue;
645 }
646
2a964810 647 m_state = SESSION_STATE_PROCESSING;
5039dede
AK
648 switch(m_wCurrentCmd)
649 {
650 case CMD_LOGIN:
711e5e9a 651 login(pMsg);
5039dede
AK
652 break;
653 case CMD_GET_SERVER_INFO:
b368969c 654 sendServerInfo(pMsg->getId());
5039dede 655 break;
5039dede 656 case CMD_GET_MY_CONFIG:
6b29839d 657 sendConfigForAgent(pMsg);
5039dede
AK
658 break;
659 case CMD_GET_OBJECTS:
62768df3
VK
660 sendAllObjects(pMsg);
661 break;
662 case CMD_GET_SELECTED_OBJECTS:
663 sendSelectedObjects(pMsg);
5039dede 664 break;
5039dede 665 case CMD_GET_CONFIG_VARLIST:
c85c8ef2
VK
666 getConfigurationVariables(pMsg->getId());
667 break;
668 case CMD_GET_PUBLIC_CONFIG_VAR:
669 getPublicConfigurationVariable(pMsg);
5039dede
AK
670 break;
671 case CMD_SET_CONFIG_VARIABLE:
c85c8ef2 672 setConfigurationVariable(pMsg);
5039dede 673 break;
c7aa788e
EJ
674 case CMD_SET_CONFIG_TO_DEFAULT:
675 setDefaultConfigurationVariableValues(pMsg);
676 break;
5039dede 677 case CMD_DELETE_CONFIG_VARIABLE:
c85c8ef2 678 deleteConfigurationVariable(pMsg);
5039dede
AK
679 break;
680 case CMD_CONFIG_GET_CLOB:
1da08bc6 681 getConfigCLOB(pMsg);
5039dede
AK
682 break;
683 case CMD_CONFIG_SET_CLOB:
1da08bc6 684 setConfigCLOB(pMsg);
5039dede 685 break;
a881eafa
VK
686 case CMD_GET_ALARM_CATEGORIES:
687 getAlarmCategories(pMsg->getId());
6a6b96c0 688 break;
a881eafa 689 case CMD_MODIFY_ALARM_CATEGORY:
6a6b96c0
EJ
690 modifyAlarmCategory(pMsg);
691 break;
a881eafa
VK
692 case CMD_DELETE_ALARM_CATEGORY:
693 deleteAlarmCategory(pMsg);
6a6b96c0 694 break;
5039dede 695 case CMD_LOAD_EVENT_DB:
fbf8ec29 696 sendEventDB(pMsg->getId());
5039dede
AK
697 break;
698 case CMD_SET_EVENT_INFO:
8eb2d92b 699 modifyEventTemplate(pMsg);
5039dede
AK
700 break;
701 case CMD_DELETE_EVENT_TEMPLATE:
8eb2d92b 702 deleteEventTemplate(pMsg);
5039dede
AK
703 break;
704 case CMD_GENERATE_EVENT_CODE:
b368969c 705 generateEventCode(pMsg->getId());
5039dede
AK
706 break;
707 case CMD_MODIFY_OBJECT:
92c51b1d 708 modifyObject(pMsg);
5039dede
AK
709 break;
710 case CMD_SET_OBJECT_MGMT_STATUS:
1da08bc6 711 changeObjectMgmtStatus(pMsg);
5039dede 712 break;
7e18667a
VK
713 case CMD_ENTER_MAINT_MODE:
714 enterMaintenanceMode(pMsg);
715 break;
716 case CMD_LEAVE_MAINT_MODE:
717 leaveMaintenanceMode(pMsg);
718 break;
5039dede 719 case CMD_LOAD_USER_DB:
b368969c 720 sendUserDB(pMsg->getId());
5039dede
AK
721 break;
722 case CMD_CREATE_USER:
b1e9b6b3 723 createUser(pMsg);
5039dede
AK
724 break;
725 case CMD_UPDATE_USER:
b1e9b6b3 726 updateUser(pMsg);
5039dede 727 break;
2d8d8ea2 728 case CMD_DETACH_LDAP_USER:
729 detachLdapUser(pMsg);
730 break;
5039dede 731 case CMD_DELETE_USER:
b1e9b6b3 732 deleteUser(pMsg);
5039dede
AK
733 break;
734 case CMD_LOCK_USER_DB:
b368969c 735 lockUserDB(pMsg->getId(), TRUE);
5039dede
AK
736 break;
737 case CMD_UNLOCK_USER_DB:
b368969c 738 lockUserDB(pMsg->getId(), FALSE);
5039dede
AK
739 break;
740 case CMD_SET_PASSWORD:
b1e9b6b3 741 setPassword(pMsg);
5039dede 742 break;
77a08c86
VK
743 case CMD_VALIDATE_PASSWORD:
744 validatePassword(pMsg);
745 break;
5039dede 746 case CMD_GET_NODE_DCI_LIST:
92c51b1d 747 openNodeDCIList(pMsg);
5039dede
AK
748 break;
749 case CMD_UNLOCK_NODE_DCI_LIST:
92c51b1d 750 closeNodeDCIList(pMsg);
5039dede
AK
751 break;
752 case CMD_CREATE_NEW_DCI:
753 case CMD_MODIFY_NODE_DCI:
754 case CMD_DELETE_NODE_DCI:
92c51b1d 755 modifyNodeDCI(pMsg);
5039dede
AK
756 break;
757 case CMD_SET_DCI_STATUS:
92c51b1d 758 changeDCIStatus(pMsg);
5039dede
AK
759 break;
760 case CMD_COPY_DCI:
92c51b1d 761 copyDCI(pMsg);
5039dede
AK
762 break;
763 case CMD_APPLY_TEMPLATE:
92c51b1d 764 applyTemplate(pMsg);
5039dede
AK
765 break;
766 case CMD_GET_DCI_DATA:
92c51b1d
VK
767 CALL_IN_NEW_THREAD(getCollectedData, pMsg);
768 break;
769 case CMD_GET_TABLE_DCI_DATA:
770 CALL_IN_NEW_THREAD(getTableCollectedData, pMsg);
5039dede
AK
771 break;
772 case CMD_CLEAR_DCI_DATA:
92c51b1d 773 CALL_IN_NEW_THREAD(clearDCIData, pMsg);
5039dede 774 break;
79633a65 775 case CMD_FORCE_DCI_POLL:
776 CALL_IN_NEW_THREAD(forceDCIPoll, pMsg);
777 break;
5039dede 778 case CMD_OPEN_EPP:
c9630390 779 openEPP(pMsg);
5039dede
AK
780 break;
781 case CMD_CLOSE_EPP:
b368969c 782 closeEPP(pMsg->getId());
5039dede
AK
783 break;
784 case CMD_SAVE_EPP:
92c51b1d 785 saveEPP(pMsg);
5039dede
AK
786 break;
787 case CMD_EPP_RECORD:
92c51b1d 788 processEPPRecord(pMsg);
5039dede
AK
789 break;
790 case CMD_GET_MIB_TIMESTAMP:
b368969c 791 sendMIBTimestamp(pMsg->getId());
5039dede
AK
792 break;
793 case CMD_GET_MIB:
b08d31f4 794 CALL_IN_NEW_THREAD(sendMib, pMsg);
5039dede
AK
795 break;
796 case CMD_CREATE_OBJECT:
1da08bc6 797 CALL_IN_NEW_THREAD(createObject, pMsg);
5039dede
AK
798 break;
799 case CMD_BIND_OBJECT:
1da08bc6 800 changeObjectBinding(pMsg, TRUE);
5039dede
AK
801 break;
802 case CMD_UNBIND_OBJECT:
1da08bc6
VK
803 changeObjectBinding(pMsg, FALSE);
804 break;
805 case CMD_ADD_CLUSTER_NODE:
806 addClusterNode(pMsg);
5039dede 807 break;
5039dede 808 case CMD_GET_ALL_ALARMS:
3ddc492b 809 CALL_IN_NEW_THREAD(getAlarms, pMsg);
5039dede 810 break;
4644eee7
VK
811 case CMD_GET_ALARM_COMMENTS:
812 getAlarmComments(pMsg);
5039dede 813 break;
b81d7b7d 814 case CMD_SET_ALARM_STATUS_FLOW:
815 updateAlarmStatusFlow(pMsg);
816 break;
4644eee7
VK
817 case CMD_UPDATE_ALARM_COMMENT:
818 updateAlarmComment(pMsg);
1b94acbf 819 break;
4644eee7
VK
820 case CMD_DELETE_ALARM_COMMENT:
821 deleteAlarmComment(pMsg);
f82a8b5d 822 break;
4d00760d
VK
823 case CMD_GET_ALARM:
824 getAlarm(pMsg);
825 break;
b1e9b6b3 826 case CMD_GET_ALARM_EVENTS:
2bac37f9 827 CALL_IN_NEW_THREAD(getAlarmEvents, pMsg);
b1e9b6b3 828 break;
5039dede 829 case CMD_ACK_ALARM:
1add6d73 830 acknowledgeAlarm(pMsg);
5039dede 831 break;
5f6bc78c
VK
832 case CMD_RESOLVE_ALARM:
833 resolveAlarm(pMsg, false);
834 break;
5039dede 835 case CMD_TERMINATE_ALARM:
a881eafa 836 resolveAlarm(pMsg, true);
5039dede
AK
837 break;
838 case CMD_DELETE_ALARM:
1add6d73 839 deleteAlarm(pMsg);
5039dede 840 break;
a881eafa
VK
841 case CMD_BULK_RESOLVE_ALARMS:
842 bulkResolveAlarms(pMsg, false);
843 break;
844 case CMD_BULK_TERMINATE_ALARMS:
845 bulkResolveAlarms(pMsg, true);
846 break;
3c35018e
VK
847 case CMD_OPEN_HELPDESK_ISSUE:
848 CALL_IN_NEW_THREAD(openHelpdeskIssue, pMsg);
849 break;
6cedeb69
VK
850 case CMD_GET_HELPDESK_URL:
851 getHelpdeskUrl(pMsg);
852 break;
1eb0b101
VK
853 case CMD_UNLINK_HELPDESK_ISSUE:
854 unlinkHelpdeskIssue(pMsg);
855 break;
5039dede 856 case CMD_CREATE_ACTION:
1b94acbf 857 createAction(pMsg);
5039dede
AK
858 break;
859 case CMD_MODIFY_ACTION:
1b94acbf 860 updateAction(pMsg);
5039dede
AK
861 break;
862 case CMD_DELETE_ACTION:
1b94acbf 863 deleteAction(pMsg);
5039dede
AK
864 break;
865 case CMD_LOAD_ACTIONS:
b368969c 866 sendAllActions(pMsg->getId());
5039dede 867 break;
5039dede 868 case CMD_DELETE_OBJECT:
f5d16551 869 deleteObject(pMsg);
5039dede
AK
870 break;
871 case CMD_POLL_NODE:
92c51b1d 872 forcedNodePoll(pMsg);
5039dede
AK
873 break;
874 case CMD_TRAP:
b1e9b6b3 875 onTrap(pMsg);
5039dede
AK
876 break;
877 case CMD_WAKEUP_NODE:
b1e9b6b3 878 onWakeUpNode(pMsg);
5039dede 879 break;
5039dede 880 case CMD_CREATE_TRAP:
fdbee7f8 881 editTrap(TRAP_CREATE, pMsg);
5039dede
AK
882 break;
883 case CMD_MODIFY_TRAP:
fdbee7f8 884 editTrap(TRAP_UPDATE, pMsg);
5039dede
AK
885 break;
886 case CMD_DELETE_TRAP:
fdbee7f8 887 editTrap(TRAP_DELETE, pMsg);
5039dede
AK
888 break;
889 case CMD_LOAD_TRAP_CFG:
b368969c 890 sendAllTraps(pMsg->getId());
5039dede
AK
891 break;
892 case CMD_GET_TRAP_CFG_RO:
b368969c 893 sendAllTraps2(pMsg->getId());
5039dede
AK
894 break;
895 case CMD_QUERY_PARAMETER:
46117060 896 CALL_IN_NEW_THREAD(queryParameter, pMsg);
5039dede 897 break;
55bdca5a
VK
898 case CMD_QUERY_TABLE:
899 CALL_IN_NEW_THREAD(queryAgentTable, pMsg);
900 break;
5039dede 901 case CMD_LOCK_PACKAGE_DB:
b368969c 902 LockPackageDB(pMsg->getId(), TRUE);
5039dede
AK
903 break;
904 case CMD_UNLOCK_PACKAGE_DB:
b368969c 905 LockPackageDB(pMsg->getId(), FALSE);
5039dede
AK
906 break;
907 case CMD_GET_PACKAGE_LIST:
b368969c 908 SendAllPackages(pMsg->getId());
5039dede
AK
909 break;
910 case CMD_INSTALL_PACKAGE:
911 InstallPackage(pMsg);
912 break;
913 case CMD_REMOVE_PACKAGE:
914 RemovePackage(pMsg);
915 break;
916 case CMD_GET_PARAMETER_LIST:
074498ac 917 getParametersList(pMsg);
5039dede
AK
918 break;
919 case CMD_DEPLOY_PACKAGE:
920 DeployPackage(pMsg);
921 break;
922 case CMD_GET_LAST_VALUES:
b9a8e081
VK
923 getLastValues(pMsg);
924 break;
2ab9314f 925 case CMD_GET_DCI_VALUES:
926 getLastValuesByDciId(pMsg);
927 break;
b9a8e081
VK
928 case CMD_GET_TABLE_LAST_VALUES:
929 getTableLastValues(pMsg);
5039dede 930 break;
711e5e9a
VK
931 case CMD_GET_THRESHOLD_SUMMARY:
932 getThresholdSummary(pMsg);
933 break;
5039dede 934 case CMD_GET_USER_VARIABLE:
fdbee7f8 935 getUserVariable(pMsg);
5039dede
AK
936 break;
937 case CMD_SET_USER_VARIABLE:
fdbee7f8 938 setUserVariable(pMsg);
5039dede
AK
939 break;
940 case CMD_DELETE_USER_VARIABLE:
fdbee7f8 941 deleteUserVariable(pMsg);
5039dede
AK
942 break;
943 case CMD_ENUM_USER_VARIABLES:
fdbee7f8 944 enumUserVariables(pMsg);
5039dede
AK
945 break;
946 case CMD_COPY_USER_VARIABLE:
fdbee7f8 947 copyUserVariable(pMsg);
5039dede 948 break;
4c789f9e
VK
949 case CMD_CHANGE_ZONE:
950 changeObjectZone(pMsg);
5039dede
AK
951 break;
952 case CMD_REQUEST_ENCRYPTION:
9e9d631e 953 setupEncryption(pMsg);
5039dede
AK
954 break;
955 case CMD_GET_AGENT_CONFIG:
92c51b1d 956 getAgentConfig(pMsg);
5039dede
AK
957 break;
958 case CMD_UPDATE_AGENT_CONFIG:
92c51b1d 959 updateAgentConfig(pMsg);
5039dede
AK
960 break;
961 case CMD_EXECUTE_ACTION:
e31c8e60 962 CALL_IN_NEW_THREAD(executeAction, pMsg);
5039dede
AK
963 break;
964 case CMD_GET_OBJECT_TOOLS:
b576249a 965 getObjectTools(pMsg->getId());
5039dede
AK
966 break;
967 case CMD_EXEC_TABLE_TOOL:
0e950f45 968 execTableTool(pMsg);
5039dede
AK
969 break;
970 case CMD_GET_OBJECT_TOOL_DETAILS:
b576249a 971 getObjectToolDetails(pMsg);
5039dede
AK
972 break;
973 case CMD_UPDATE_OBJECT_TOOL:
0e950f45 974 updateObjectTool(pMsg);
5039dede
AK
975 break;
976 case CMD_DELETE_OBJECT_TOOL:
0e950f45 977 deleteObjectTool(pMsg);
5039dede 978 break;
9dd47420 979 case CMD_CHANGE_OBJECT_TOOL_STATUS:
6f8e39e5 980 changeObjectToolStatus(pMsg);
03f4f212 981 break;
5039dede 982 case CMD_GENERATE_OBJECT_TOOL_ID:
b368969c 983 generateObjectToolId(pMsg->getId());
5039dede
AK
984 break;
985 case CMD_CHANGE_SUBSCRIPTION:
b1e9b6b3 986 changeSubscription(pMsg);
5039dede 987 break;
5039dede 988 case CMD_GET_SERVER_STATS:
b368969c 989 sendServerStats(pMsg->getId());
5039dede
AK
990 break;
991 case CMD_GET_SCRIPT_LIST:
b368969c 992 sendScriptList(pMsg->getId());
5039dede
AK
993 break;
994 case CMD_GET_SCRIPT:
0c7aca90 995 sendScript(pMsg);
5039dede
AK
996 break;
997 case CMD_UPDATE_SCRIPT:
0c7aca90 998 updateScript(pMsg);
5039dede
AK
999 break;
1000 case CMD_RENAME_SCRIPT:
0c7aca90 1001 renameScript(pMsg);
5039dede
AK
1002 break;
1003 case CMD_DELETE_SCRIPT:
0c7aca90 1004 deleteScript(pMsg);
5039dede
AK
1005 break;
1006 case CMD_GET_SESSION_LIST:
b368969c 1007 SendSessionList(pMsg->getId());
5039dede
AK
1008 break;
1009 case CMD_KILL_SESSION:
1010 KillSession(pMsg);
1011 break;
5039dede
AK
1012 case CMD_START_SNMP_WALK:
1013 StartSnmpWalk(pMsg);
5039dede
AK
1014 break;
1015 case CMD_RESOLVE_DCI_NAMES:
241c2740 1016 resolveDCINames(pMsg);
5039dede
AK
1017 break;
1018 case CMD_GET_DCI_INFO:
1019 SendDCIInfo(pMsg);
1020 break;
071fd171
VK
1021 case CMD_GET_DCI_THRESHOLDS:
1022 sendDCIThresholds(pMsg);
1023 break;
5039dede 1024 case CMD_GET_DCI_EVENTS_LIST:
25a1e9d0
VK
1025 getDCIEventList(pMsg);
1026 break;
1027 case CMD_GET_DCI_SCRIPT_LIST:
1028 getDCIScriptList(pMsg);
5039dede 1029 break;
74526d25
VK
1030 case CMD_GET_PERFTAB_DCI_LIST:
1031 sendPerfTabDCIList(pMsg);
5039dede
AK
1032 break;
1033 case CMD_PUSH_DCI_DATA:
6fd6de0a 1034 pushDCIData(pMsg);
5039dede
AK
1035 break;
1036 case CMD_GET_AGENT_CFG_LIST:
b368969c 1037 sendAgentCfgList(pMsg->getId());
5039dede
AK
1038 break;
1039 case CMD_OPEN_AGENT_CONFIG:
1040 OpenAgentConfig(pMsg);
1041 break;
1042 case CMD_SAVE_AGENT_CONFIG:
1043 SaveAgentConfig(pMsg);
1044 break;
1045 case CMD_DELETE_AGENT_CONFIG:
1046 DeleteAgentConfig(pMsg);
1047 break;
1048 case CMD_SWAP_AGENT_CONFIGS:
1049 SwapAgentConfigs(pMsg);
1050 break;
1051 case CMD_GET_OBJECT_COMMENTS:
1052 SendObjectComments(pMsg);
1053 break;
1054 case CMD_UPDATE_OBJECT_COMMENTS:
6fd6de0a 1055 updateObjectComments(pMsg);
5039dede
AK
1056 break;
1057 case CMD_GET_ADDR_LIST:
6fd6de0a 1058 getAddrList(pMsg);
5039dede
AK
1059 break;
1060 case CMD_SET_ADDR_LIST:
6fd6de0a 1061 setAddrList(pMsg);
5039dede
AK
1062 break;
1063 case CMD_RESET_COMPONENT:
92c51b1d 1064 resetComponent(pMsg);
5039dede 1065 break;
a7ff20a5
VK
1066 case CMD_EXPORT_CONFIGURATION:
1067 exportConfiguration(pMsg);
5039dede 1068 break;
a7ff20a5 1069 case CMD_IMPORT_CONFIGURATION:
78ccd7b4 1070 CALL_IN_NEW_THREAD(importConfiguration, pMsg);
5039dede
AK
1071 break;
1072 case CMD_GET_GRAPH_LIST:
aed41472 1073 sendGraphList(pMsg);
5039dede 1074 break;
7a4c94ee 1075 case CMD_SAVE_GRAPH:
6f8e39e5 1076 saveGraph(pMsg);
7a4c94ee 1077 break;
5039dede 1078 case CMD_DELETE_GRAPH:
6f8e39e5 1079 deleteGraph(pMsg);
5039dede
AK
1080 break;
1081 case CMD_ADD_CA_CERTIFICATE:
493beadc 1082 addCACertificate(pMsg);
5039dede
AK
1083 break;
1084 case CMD_DELETE_CERTIFICATE:
493beadc 1085 deleteCertificate(pMsg);
5039dede
AK
1086 break;
1087 case CMD_UPDATE_CERT_COMMENTS:
493beadc 1088 updateCertificateComments(pMsg);
5039dede
AK
1089 break;
1090 case CMD_GET_CERT_LIST:
b368969c 1091 getCertificateList(pMsg->getId());
5039dede
AK
1092 break;
1093 case CMD_QUERY_L2_TOPOLOGY:
84880c89 1094 CALL_IN_NEW_THREAD(queryL2Topology, pMsg);
5039dede
AK
1095 break;
1096 case CMD_SEND_SMS:
b1e9b6b3 1097 sendSMS(pMsg);
5039dede
AK
1098 break;
1099 case CMD_GET_COMMUNITY_LIST:
b368969c 1100 SendCommunityList(pMsg->getId());
5039dede
AK
1101 break;
1102 case CMD_UPDATE_COMMUNITY_LIST:
1103 UpdateCommunityList(pMsg);
1104 break;
df8a4ca2 1105 case CMD_GET_USM_CREDENTIALS:
b368969c 1106 sendUsmCredentials(pMsg->getId());
df8a4ca2
VK
1107 break;
1108 case CMD_UPDATE_USM_CREDENTIALS:
1109 updateUsmCredentials(pMsg);
1110 break;
00420032 1111 case CMD_GET_PERSISTENT_STORAGE:
1112 getPersistantStorage(pMsg->getId());
5039dede 1113 break;
00420032 1114 case CMD_SET_PSTORAGE_VALUE:
1115 setPstorageValue(pMsg);
5039dede 1116 break;
00420032 1117 case CMD_DELETE_PSTORAGE_VALUE:
1118 deletePstorageValue(pMsg);
5039dede 1119 break;
5039dede 1120 case CMD_REGISTER_AGENT:
1da08bc6 1121 registerAgent(pMsg);
5039dede
AK
1122 break;
1123 case CMD_GET_SERVER_FILE:
1da08bc6 1124 CALL_IN_NEW_THREAD(getServerFile, pMsg);
5039dede 1125 break;
6f16f12d
VK
1126 case CMD_GET_AGENT_FILE:
1127 CALL_IN_NEW_THREAD(getAgentFile, pMsg);
1128 break;
9fa031cd 1129 case CMD_CANCEL_FILE_MONITORING:
1130 CALL_IN_NEW_THREAD(cancelFileMonitoring, pMsg);
1131 break;
4d0c32f3 1132 case CMD_TEST_DCI_TRANSFORMATION:
1da08bc6 1133 testDCITransformation(pMsg);
4d0c32f3 1134 break;
529956a0 1135 case CMD_EXECUTE_SCRIPT:
1136 CALL_IN_NEW_THREAD(executeScript, pMsg);
1137 break;
e9bf9011
VK
1138 case CMD_EXECUTE_LIBRARY_SCRIPT:
1139 CALL_IN_NEW_THREAD(executeLibraryScript, pMsg);
1140 break;
ab621f39 1141 case CMD_GET_JOB_LIST:
b368969c 1142 sendJobList(pMsg->getId());
ab621f39 1143 break;
f40831eb 1144 case CMD_CANCEL_JOB:
45d84f8a
VK
1145 cancelJob(pMsg);
1146 break;
8d9f7450
VK
1147 case CMD_HOLD_JOB:
1148 holdJob(pMsg);
1149 break;
1150 case CMD_UNHOLD_JOB:
1151 unholdJob(pMsg);
1152 break;
45d84f8a 1153 case CMD_DEPLOY_AGENT_POLICY:
93599cfd
VK
1154 deployAgentPolicy(pMsg, false);
1155 break;
1156 case CMD_UNINSTALL_AGENT_POLICY:
1157 deployAgentPolicy(pMsg, true);
f40831eb 1158 break;
d83dc1f0
VK
1159 case CMD_GET_CURRENT_USER_ATTR:
1160 getUserCustomAttribute(pMsg);
1161 break;
1162 case CMD_SET_CURRENT_USER_ATTR:
1163 setUserCustomAttribute(pMsg);
1164 break;
e05b1945
VK
1165 case CMD_OPEN_SERVER_LOG:
1166 openServerLog(pMsg);
1167 break;
1168 case CMD_CLOSE_SERVER_LOG:
1169 closeServerLog(pMsg);
1170 break;
1171 case CMD_QUERY_LOG:
1172 CALL_IN_NEW_THREAD(queryServerLog, pMsg);
1173 break;
1174 case CMD_GET_LOG_DATA:
1175 CALL_IN_NEW_THREAD(getServerLogQueryData, pMsg);
1176 break;
630e15d6
VK
1177 case CMD_FIND_NODE_CONNECTION:
1178 CALL_IN_NEW_THREAD(findNodeConnection, pMsg);
1179 break;
06a93345
VK
1180 case CMD_FIND_MAC_LOCATION:
1181 CALL_IN_NEW_THREAD(findMacAddress, pMsg);
1182 break;
80e0db05
VK
1183 case CMD_FIND_IP_LOCATION:
1184 CALL_IN_NEW_THREAD(findIpAddress, pMsg);
1185 break;
f1984eb9
EJ
1186 case CMD_FIND_HOSTNAME_LOCATION:
1187 CALL_IN_NEW_THREAD(findHostname, pMsg);
1188 break;
e6b9439a
AK
1189 case CMD_GET_IMAGE:
1190 sendLibraryImage(pMsg);
1191 break;
1192 case CMD_CREATE_IMAGE:
1193 updateLibraryImage(pMsg);
1194 break;
1195 case CMD_DELETE_IMAGE:
1196 deleteLibraryImage(pMsg);
1197 break;
1198 case CMD_MODIFY_IMAGE:
1199 updateLibraryImage(pMsg);
1200 break;
1201 case CMD_LIST_IMAGES:
1202 listLibraryImages(pMsg);
1203 break;
f69c6203
VK
1204 case CMD_EXECUTE_SERVER_COMMAND:
1205 executeServerCommand(pMsg);
1206 break;
e5b8d60e 1207 case CMD_STOP_SERVER_COMMAND:
45ac5dd0
EJ
1208 stopServerCommand(pMsg);
1209 break;
1a5e0c22
VK
1210 case CMD_LIST_SERVER_FILES:
1211 listServerFileStore(pMsg);
1212 break;
619e5c9b
VK
1213 case CMD_UPLOAD_FILE_TO_AGENT:
1214 uploadFileToAgent(pMsg);
1215 break;
68f898c9
VK
1216 case CMD_UPLOAD_FILE:
1217 receiveFile(pMsg);
1218 break;
1219 case CMD_DELETE_FILE:
1220 deleteFile(pMsg);
1221 break;
200d662d 1222 case CMD_OPEN_CONSOLE:
b368969c 1223 openConsole(pMsg->getId());
200d662d
VK
1224 break;
1225 case CMD_CLOSE_CONSOLE:
b368969c 1226 closeConsole(pMsg->getId());
200d662d
VK
1227 break;
1228 case CMD_ADM_REQUEST:
1229 CALL_IN_NEW_THREAD(processConsoleCommand, pMsg);
1230 break;
7f632dfe
VK
1231 case CMD_GET_VLANS:
1232 getVlans(pMsg);
1233 break;
6d069676
VK
1234 case CMD_GET_NETWORK_PATH:
1235 CALL_IN_NEW_THREAD(getNetworkPath, pMsg);
1236 break;
8836184f
VK
1237 case CMD_GET_NODE_COMPONENTS:
1238 getNodeComponents(pMsg);
1239 break;
caa04e26
VK
1240 case CMD_GET_NODE_SOFTWARE:
1241 getNodeSoftware(pMsg);
1242 break;
46ee6286
VK
1243 case CMD_GET_WINPERF_OBJECTS:
1244 getWinPerfObjects(pMsg);
1245 break;
fdbee7f8
VK
1246 case CMD_LIST_MAPPING_TABLES:
1247 listMappingTables(pMsg);
1248 break;
1249 case CMD_GET_MAPPING_TABLE:
1250 getMappingTable(pMsg);
1251 break;
1252 case CMD_UPDATE_MAPPING_TABLE:
1253 updateMappingTable(pMsg);
1254 break;
1255 case CMD_DELETE_MAPPING_TABLE:
1256 deleteMappingTable(pMsg);
1257 break;
d5de1d1d
VK
1258 case CMD_GET_WIRELESS_STATIONS:
1259 getWirelessStations(pMsg);
1260 break;
b4c2a628 1261 case CMD_GET_SUMMARY_TABLES:
b368969c 1262 getSummaryTables(pMsg->getId());
b4c2a628
VK
1263 break;
1264 case CMD_GET_SUMMARY_TABLE_DETAILS:
1265 getSummaryTableDetails(pMsg);
1266 break;
1267 case CMD_MODIFY_SUMMARY_TABLE:
1268 modifySummaryTable(pMsg);
1269 break;
1270 case CMD_DELETE_SUMMARY_TABLE:
1271 deleteSummaryTable(pMsg);
1272 break;
1273 case CMD_QUERY_SUMMARY_TABLE:
1274 querySummaryTable(pMsg);
1275 break;
5389f7b0
VK
1276 case CMD_QUERY_ADHOC_SUMMARY_TABLE:
1277 queryAdHocSummaryTable(pMsg);
1278 break;
ceb0fc8d
VK
1279 case CMD_GET_SUBNET_ADDRESS_MAP:
1280 getSubnetAddressMap(pMsg);
1281 break;
d39de9a8
VK
1282 case CMD_GET_EFFECTIVE_RIGHTS:
1283 getEffectiveRights(pMsg);
1284 break;
f3e2e618 1285 case CMD_GET_FOLDER_SIZE:
d9821bd7 1286 case CMD_GET_FOLDER_CONTENT:
7cf549ad 1287 case CMD_FILEMGR_DELETE_FILE:
1288 case CMD_FILEMGR_RENAME_FILE:
1289 case CMD_FILEMGR_MOVE_FILE:
5de546a2 1290 case CMD_FILEMGR_CREATE_FOLDER:
74d0b136 1291 CALL_IN_NEW_THREAD(fileManagerControl, pMsg);
7cf549ad 1292 break;
1293 case CMD_FILEMGR_UPLOAD:
1294 CALL_IN_NEW_THREAD(uploadUserFileToAgent, pMsg);
d9821bd7 1295 break;
c44cf458
VK
1296 case CMD_GET_SWITCH_FDB:
1297 CALL_IN_NEW_THREAD(getSwitchForwardingDatabase, pMsg);
1298 break;
1299 case CMD_GET_ROUTING_TABLE:
1300 CALL_IN_NEW_THREAD(getRoutingTable, pMsg);
1301 break;
4899db4d 1302 case CMD_GET_LOC_HISTORY:
1303 CALL_IN_NEW_THREAD(getLocationHistory, pMsg);
1304 break;
d9e5a5be 1305 case CMD_TAKE_SCREENSHOT:
1306 getScreenshot(pMsg);
1307 break;
5f573844
VK
1308 case CMD_COMPILE_SCRIPT:
1309 compileScript(pMsg);
1310 break;
4b535d78 1311 case CMD_CLEAN_AGENT_DCI_CONF:
1312 cleanAgentDciConfiguration(pMsg);
1313 break;
1314 case CMD_RESYNC_AGENT_DCI_CONF:
1315 resyncAgentDciConfiguration(pMsg);
1316 break;
a44a910c 1317 case CMD_LIST_SCHEDULE_CALLBACKS:
ec13a467 1318 getSchedulerTaskHandlers(pMsg);
a44a910c 1319 break;
1320 case CMD_LIST_SCHEDULES:
ec13a467 1321 getScheduledTasks(pMsg);
a44a910c 1322 break;
1323 case CMD_ADD_SCHEDULE:
ec13a467 1324 addScheduledTask(pMsg);
a44a910c 1325 break;
1326 case CMD_UPDATE_SCHEDULE:
ec13a467 1327 updateScheduledTask(pMsg);
a44a910c 1328 break;
1329 case CMD_REMOVE_SCHEDULE:
ec13a467 1330 removeScheduledTask(pMsg);
d6aca8c9 1331 break;
badd6e08
VK
1332 case CMD_GET_REPOSITORIES:
1333 CALL_IN_NEW_THREAD(getRepositories, pMsg);
1334 break;
1335 case CMD_ADD_REPOSITORY:
1336 CALL_IN_NEW_THREAD(addRepository, pMsg);
1337 break;
1338 case CMD_MODIFY_REPOSITORY:
1339 CALL_IN_NEW_THREAD(modifyRepository, pMsg);
1340 break;
1341 case CMD_DELETE_REPOSITORY:
1342 CALL_IN_NEW_THREAD(deleteRepository, pMsg);
1343 break;
3c463101
VK
1344 case CMD_GET_AGENT_TUNNELS:
1345 getAgentTunnels(pMsg);
3b89a4c1
VK
1346 break;
1347 case CMD_BIND_AGENT_TUNNEL:
1348 bindAgentTunnel(pMsg);
1349 break;
c733fcc4
VK
1350 case CMD_UNBIND_AGENT_TUNNEL:
1351 unbindAgentTunnel(pMsg);
1352 break;
0cf6fcbd
VK
1353 case CMD_GET_PREDICTION_ENGINES:
1354 getPredictionEngines(pMsg);
1355 break;
1356 case CMD_GET_PREDICTED_DATA:
1357 CALL_IN_NEW_THREAD(getPredictedData, pMsg);
1358 break;
4ef60905
AK
1359#ifdef WITH_ZMQ
1360 case CMD_ZMQ_SUBSCRIBE_EVENT:
1361 zmqManageSubscription(pMsg, zmq::EVENT, true);
1362 break;
1363 case CMD_ZMQ_UNSUBSCRIBE_EVENT:
1364 zmqManageSubscription(pMsg, zmq::EVENT, false);
1365 break;
1366 case CMD_ZMQ_SUBSCRIBE_DATA:
1367 zmqManageSubscription(pMsg, zmq::DATA, true);
1368 break;
1369 case CMD_ZMQ_UNSUBSCRIBE_DATA:
1370 zmqManageSubscription(pMsg, zmq::DATA, false);
1371 break;
529c5844 1372 case CMD_ZMQ_GET_EVT_SUBSCRIPTIONS:
4ef60905
AK
1373 zmqListSubscriptions(pMsg, zmq::EVENT);
1374 break;
529c5844 1375 case CMD_ZMQ_GET_DATA_SUBSCRIPTIONS:
4ef60905
AK
1376 zmqListSubscriptions(pMsg, zmq::DATA);
1377 break;
1378#endif
5039dede 1379 default:
d75003e1
AK
1380 if ((m_wCurrentCmd >> 8) == 0x11)
1381 {
1382 // Reporting Server range (0x1100 - 0x11FF)
1383 CALL_IN_NEW_THREAD(forwardToReportingServer, pMsg);
1384 break;
1385 }
1386
5039dede
AK
1387 // Pass message to loaded modules
1388 for(i = 0; i < g_dwNumModules; i++)
1389 {
534e1b83 1390 if (g_pModuleList[i].pfClientCommandHandler != NULL)
5039dede 1391 {
534e1b83 1392 status = g_pModuleList[i].pfClientCommandHandler(m_wCurrentCmd, pMsg, this);
5039dede
AK
1393 if (status != NXMOD_COMMAND_IGNORED)
1394 {
1395 if (status == NXMOD_COMMAND_ACCEPTED_ASYNC)
1396 {
1397 pMsg = NULL; // Prevent deletion
5039dede
AK
1398 }
1399 break; // Message was processed by the module
1400 }
1401 }
1402 }
1403 if (i == g_dwNumModules)
1404 {
b368969c 1405 NXCPMessage response;
5039dede 1406
b368969c
VK
1407 response.setId(pMsg->getId());
1408 response.setCode(CMD_REQUEST_COMPLETED);
1409 response.setField(VID_RCC, RCC_NOT_IMPLEMENTED);
e05b1945 1410 sendMessage(&response);
5039dede
AK
1411 }
1412 break;
1413 }
1414 delete pMsg;
2a964810 1415 m_state = (m_dwFlags & CSF_AUTHENTICATED) ? SESSION_STATE_IDLE : SESSION_STATE_INIT;
5039dede
AK
1416 }
1417}
1418
534e1b83
VK
1419/**
1420 * Respond to client's keepalive message
1421 */
967893bb 1422void ClientSession::respondToKeepalive(UINT32 dwRqId)
5039dede 1423{
b368969c 1424 NXCPMessage msg;
5039dede 1425
b368969c
VK
1426 msg.setCode(CMD_REQUEST_COMPLETED);
1427 msg.setId(dwRqId);
1428 msg.setField(VID_RCC, RCC_SUCCESS);
e05b1945 1429 sendMessage(&msg);
5039dede
AK
1430}
1431
6fd6de0a
VK
1432/**
1433 * Send message to client
1434 */
a07511b5 1435bool ClientSession::sendMessage(NXCPMessage *msg)
d3a7cf4c 1436{
134c3d00 1437 if (isTerminated())
a07511b5 1438 return false;
134c3d00 1439
4970ef34 1440 NXCP_MESSAGE *rawMsg = msg->createMessage((m_dwFlags & CSF_COMPRESSION_ENABLED) != 0);
8ec102ac 1441
4970ef34 1442 if ((nxlog_get_debug_level() >= 6) && (msg->getCode() != CMD_ADM_MESSAGE))
934f53da 1443 {
4970ef34
VK
1444 TCHAR buffer[128];
1445 debugPrintf(6, _T("Sending%s message %s (%d bytes)"),
1446 (ntohs(rawMsg->flags) & MF_COMPRESSED) ? _T(" compressed") : _T(""), NXCPMessageCodeName(msg->getCode(), buffer), ntohl(rawMsg->size));
1447 if (nxlog_get_debug_level() >= 8)
1448 {
1449 String msgDump = NXCPMessage::dump(rawMsg, NXCP_VERSION);
1450 debugPrintf(8, _T("Message dump:\n%s"), (const TCHAR *)msgDump);
1451 }
934f53da 1452 }
6be0a20b
VK
1453
1454 bool result;
d3a7cf4c
VK
1455 if (m_pCtx != NULL)
1456 {
b368969c 1457 NXCP_ENCRYPTED_MESSAGE *enMsg = m_pCtx->encryptMessage(rawMsg);
6be0a20b 1458 if (enMsg != NULL)
d3a7cf4c 1459 {
b368969c 1460 result = (SendEx(m_hSocket, (char *)enMsg, ntohl(enMsg->size), 0, m_mutexSocketWrite) == (int)ntohl(enMsg->size));
6be0a20b 1461 free(enMsg);
d3a7cf4c
VK
1462 }
1463 else
1464 {
6be0a20b 1465 result = false;
d3a7cf4c
VK
1466 }
1467 }
1468 else
1469 {
b368969c 1470 result = (SendEx(m_hSocket, (const char *)rawMsg, ntohl(rawMsg->size), 0, m_mutexSocketWrite) == (int)ntohl(rawMsg->size));
d3a7cf4c 1471 }
6be0a20b 1472 free(rawMsg);
d3a7cf4c 1473
6be0a20b 1474 if (!result)
d3a7cf4c
VK
1475 {
1476 closesocket(m_hSocket);
1477 m_hSocket = -1;
1478 }
a07511b5 1479 return result;
d3a7cf4c
VK
1480}
1481
534e1b83
VK
1482/**
1483 * Send raw message to client
1484 */
b368969c 1485void ClientSession::sendRawMessage(NXCP_MESSAGE *msg)
92c51b1d 1486{
134c3d00
VK
1487 if (isTerminated())
1488 return;
1489
1490 UINT16 code = htons(msg->code);
4970ef34 1491 if ((code != CMD_ADM_MESSAGE) && (nxlog_get_debug_level() >= 6))
134c3d00
VK
1492 {
1493 TCHAR buffer[128];
4970ef34
VK
1494 debugPrintf(6, _T("Sending%s message %s (%d bytes)"),
1495 (ntohs(msg->flags) & MF_COMPRESSED) ? _T(" compressed") : _T(""), NXCPMessageCodeName(ntohs(msg->code), buffer), ntohl(msg->size));
1496 if (nxlog_get_debug_level() >= 8)
1497 {
1498 String msgDump = NXCPMessage::dump(msg, NXCP_VERSION);
1499 debugPrintf(8, _T("Message dump:\n%s"), (const TCHAR *)msgDump);
1500 }
134c3d00 1501 }
92c51b1d 1502
6be0a20b 1503 bool result;
92c51b1d
VK
1504 if (m_pCtx != NULL)
1505 {
b368969c 1506 NXCP_ENCRYPTED_MESSAGE *enMsg = m_pCtx->encryptMessage(msg);
6be0a20b 1507 if (enMsg != NULL)
92c51b1d 1508 {
b368969c 1509 result = (SendEx(m_hSocket, (char *)enMsg, ntohl(enMsg->size), 0, m_mutexSocketWrite) == (int)ntohl(enMsg->size));
6be0a20b 1510 free(enMsg);
92c51b1d
VK
1511 }
1512 else
1513 {
6be0a20b 1514 result = false;
92c51b1d
VK
1515 }
1516 }
1517 else
1518 {
b368969c 1519 result = (SendEx(m_hSocket, (const char *)msg, ntohl(msg->size), 0, m_mutexSocketWrite) == (int)ntohl(msg->size));
92c51b1d
VK
1520 }
1521
6be0a20b 1522 if (!result)
92c51b1d
VK
1523 {
1524 closesocket(m_hSocket);
1525 m_hSocket = -1;
1526 }
1527}
1528
534e1b83
VK
1529/**
1530 * Send file to client
1531 */
cc022855 1532BOOL ClientSession::sendFile(const TCHAR *file, UINT32 dwRqId, long ofset)
a0e3917e 1533{
09008413
VK
1534 return !isTerminated() ? SendFileOverNXCP(m_hSocket, dwRqId, file, m_pCtx,
1535 ofset, NULL, NULL, m_mutexSocketWrite, isCompressionEnabled() ? NXCP_STREAM_COMPRESSION_DEFLATE : NXCP_STREAM_COMPRESSION_NONE) : FALSE;
a0e3917e
VK
1536}
1537
534e1b83
VK
1538/**
1539 * Send server information to client
1540 */
967893bb 1541void ClientSession::sendServerInfo(UINT32 dwRqId)
5039dede 1542{
e5390fb5
VK
1543 static UINT32 protocolVersions[] = {
1544 CLIENT_PROTOCOL_VERSION_BASE,
1545 CLIENT_PROTOCOL_VERSION_ALARMS,
1546 CLIENT_PROTOCOL_VERSION_PUSH,
1547 CLIENT_PROTOCOL_VERSION_TRAP,
1548 CLIENT_PROTOCOL_VERSION_MOBILE,
1549 CLIENT_PROTOCOL_VERSION_FULL
1550 };
b368969c 1551 NXCPMessage msg;
2589cc10 1552 TCHAR szBuffer[MAX_CONFIG_VALUE];
5039dede
AK
1553 String strURL;
1554
1555 // Prepare response message
b368969c
VK
1556 msg.setCode(CMD_REQUEST_COMPLETED);
1557 msg.setId(dwRqId);
5039dede
AK
1558
1559 // Generate challenge for certificate authentication
1560#ifdef _WITH_ENCRYPTION
1561 RAND_bytes(m_challenge, CLIENT_CHALLENGE_SIZE);
1562#else
1563 memset(m_challenge, 0, CLIENT_CHALLENGE_SIZE);
1564#endif
1565
1566 // Fill message with server info
b368969c
VK
1567 msg.setField(VID_RCC, RCC_SUCCESS);
1568 msg.setField(VID_SERVER_VERSION, NETXMS_VERSION_STRING);
e9902466 1569 msg.setField(VID_SERVER_ID, g_serverId);
b368969c 1570 msg.setField(VID_SUPPORTED_ENCRYPTION, (UINT32)0);
e5390fb5
VK
1571 msg.setField(VID_PROTOCOL_VERSION, (UINT32)CLIENT_PROTOCOL_VERSION_BASE);
1572 msg.setFieldFromInt32Array(VID_PROTOCOL_VERSION_EX, sizeof(protocolVersions) / sizeof(UINT32), protocolVersions);
b368969c
VK
1573 msg.setField(VID_CHALLENGE, m_challenge, CLIENT_CHALLENGE_SIZE);
1574 msg.setField(VID_TIMESTAMP, (UINT32)time(NULL));
5039dede
AK
1575
1576#if defined(_WIN32)
1577 TIME_ZONE_INFORMATION tz;
1578 WCHAR wst[4], wdt[8], *curr;
1579 int i;
1580
44dac3da 1581 DWORD tzType = GetTimeZoneInformation(&tz);
5039dede
AK
1582
1583 // Create 3 letter abbreviation for standard name
1584 for(i = 0, curr = tz.StandardName; (*curr != 0) && (i < 3); curr++)
1585 if (iswupper(*curr))
1586 wst[i++] = *curr;
1587 while(i < 3)
1588 wst[i++] = L'X';
1589 wst[i] = 0;
1590
1591 // Create abbreviation for DST name
1592 for(i = 0, curr = tz.DaylightName; (*curr != 0) && (i < 7); curr++)
1593 if (iswupper(*curr))
1594 wdt[i++] = *curr;
1595 while(i < 3)
1596 wdt[i++] = L'X';
1597 wdt[i] = 0;
1598
44dac3da
VK
1599 LONG effectiveBias;
1600 switch(tzType)
1601 {
1602 case TIME_ZONE_ID_STANDARD:
1603 effectiveBias = tz.Bias + tz.StandardBias;
1604 break;
1605 case TIME_ZONE_ID_DAYLIGHT:
1606 effectiveBias = tz.Bias + tz.DaylightBias;
1607 break;
1608 case TIME_ZONE_ID_UNKNOWN:
1609 effectiveBias = tz.Bias;
1610 break;
1611 default: // error
1612 effectiveBias = 0;
1613 debugPrintf(4, _T("GetTimeZoneInformation() call failed"));
1614 break;
1615 }
1616
5039dede 1617#ifdef UNICODE
44dac3da
VK
1618 swprintf(szBuffer, 1024, L"%s%c%02d%s", wst, (effectiveBias > 0) ? '-' : '+',
1619 abs(effectiveBias) / 60, (tz.DaylightBias != 0) ? wdt : L"");
5039dede 1620#else
44dac3da
VK
1621 sprintf(szBuffer, "%S%c%02d%S", wst, (effectiveBias > 0) ? '-' : '+',
1622 abs(effectiveBias) / 60, (tz.DaylightBias != 0) ? wdt : L"");
5039dede 1623#endif
d2b34835
VK
1624
1625#elif HAVE_TM_GMTOFF /* not Windows but have tm_gmtoff */
1626
1627 time_t t = time(NULL);
5039dede
AK
1628 int gmtOffset;
1629#if HAVE_LOCALTIME_R
1630 struct tm tmbuff;
d2b34835 1631 struct tm *loc = localtime_r(&t, &tmbuff);
5039dede 1632#else
d2b34835 1633 struct tm *loc = localtime(&t);
5039dede 1634#endif
2aa5fe1d 1635 gmtOffset = loc->tm_gmtoff / 3600;
dda7c270
VK
1636#ifdef UNICODE
1637 swprintf(szBuffer, 1024, L"%hs%hc%02d%hs", tzname[0], (gmtOffset >= 0) ? '+' : '-',
1638 abs(gmtOffset), (tzname[1] != NULL) ? tzname[1] : "");
1639#else
5039dede
AK
1640 sprintf(szBuffer, "%s%c%02d%s", tzname[0], (gmtOffset >= 0) ? '+' : '-',
1641 abs(gmtOffset), (tzname[1] != NULL) ? tzname[1] : "");
dda7c270 1642#endif
d2b34835
VK
1643
1644#else /* not Windows and no tm_gmtoff */
1645
1646 time_t t = time(NULL);
1647#if HAVE_GMTIME_R
b7e064e7
VK
1648 struct tm tmbuff;
1649 struct tm *gmt = gmtime_r(&t, &tmbuff);
d2b34835 1650#else
b7e064e7 1651 struct tm *gmt = gmtime(&t);
d2b34835
VK
1652#endif
1653 gmt->tm_isdst = -1;
1654 int gmtOffset = (int)((t - mktime(gmt)) / 3600);
1655#ifdef UNICODE
1656 swprintf(szBuffer, 1024, L"%hs%hc%02d%hs", tzname[0], (gmtOffset >= 0) ? '+' : '-',
1657 abs(gmtOffset), (tzname[1] != NULL) ? tzname[1] : "");
5039dede 1658#else
d2b34835
VK
1659 sprintf(szBuffer, "%s%c%02d%s", tzname[0], (gmtOffset >= 0) ? '+' : '-',
1660 abs(gmtOffset), (tzname[1] != NULL) ? tzname[1] : "");
1661#endif
1662
5039dede 1663#endif
d2b34835 1664
b368969c 1665 msg.setField(VID_TIMEZONE, szBuffer);
534e1b83 1666 debugPrintf(2, _T("Server time zone: %s"), szBuffer);
5039dede 1667
2589cc10 1668 ConfigReadStr(_T("TileServerURL"), szBuffer, MAX_CONFIG_VALUE, _T("http://tile.openstreetmap.org/"));
b368969c 1669 msg.setField(VID_TILE_SERVER_URL, szBuffer);
fceea457 1670
2589cc10 1671 ConfigReadStr(_T("DefaultConsoleDateFormat"), szBuffer, MAX_CONFIG_VALUE, _T("dd.MM.yyyy"));
b368969c 1672 msg.setField(VID_DATE_FORMAT, szBuffer);
aabe5b72 1673
2589cc10 1674 ConfigReadStr(_T("DefaultConsoleTimeFormat"), szBuffer, MAX_CONFIG_VALUE, _T("HH:mm:ss"));
b368969c 1675 msg.setField(VID_TIME_FORMAT, szBuffer);
aabe5b72 1676
2589cc10 1677 ConfigReadStr(_T("DefaultConsoleShortTimeFormat"), szBuffer, MAX_CONFIG_VALUE, _T("HH:mm"));
b368969c 1678 msg.setField(VID_SHORT_TIME_FORMAT, szBuffer);
bc969eaf 1679
4fd0b7ca
VK
1680 FillComponentsMessage(&msg);
1681
5039dede 1682 // Send response
e05b1945 1683 sendMessage(&msg);
5039dede
AK
1684}
1685
534e1b83
VK
1686/**
1687 * Authenticate client
1688 */
b368969c 1689void ClientSession::login(NXCPMessage *pRequest)
5039dede 1690{
b368969c 1691 NXCPMessage msg;
60557d06 1692 TCHAR szLogin[MAX_USER_NAME], szPassword[1024];
5039dede 1693 int nAuthType;
ab185583 1694 bool changePasswd = false, intruderLockout = false;
967893bb 1695 UINT32 dwResult;
5039dede
AK
1696#ifdef _WITH_ENCRYPTION
1697 X509 *pCert;
1698#endif
1699
1700 // Prepare response message
b368969c
VK
1701 msg.setCode(CMD_LOGIN_RESP);
1702 msg.setId(pRequest->getId());
5039dede
AK
1703
1704 // Get client info string
5c44534b 1705 if (pRequest->isFieldExist(VID_CLIENT_INFO))
5039dede
AK
1706 {
1707 TCHAR szClientInfo[32], szOSInfo[32], szLibVersion[16];
7a4c94ee 1708
b368969c
VK
1709 pRequest->getFieldAsString(VID_CLIENT_INFO, szClientInfo, 32);
1710 pRequest->getFieldAsString(VID_OS_INFO, szOSInfo, 32);
1711 pRequest->getFieldAsString(VID_LIBNXCL_VERSION, szLibVersion, 16);
77a08c86 1712 _sntprintf(m_clientInfo, 96, _T("%s (%s; libnxcl %s)"), szClientInfo, szOSInfo, szLibVersion);
5039dede
AK
1713 }
1714
b368969c 1715 m_clientType = pRequest->getFieldAsUInt16(VID_CLIENT_TYPE);
f8c6f10f
VK
1716 if ((m_clientType < 0) || (m_clientType > CLIENT_TYPE_APPLICATION))
1717 m_clientType = CLIENT_TYPE_DESKTOP;
1718
91f6b72c
VK
1719 if (m_clientType == CLIENT_TYPE_WEB)
1720 {
1721 _tcscpy(m_webServerAddress, m_workstation);
5c44534b 1722 if (pRequest->isFieldExist(VID_CLIENT_ADDRESS))
91f6b72c 1723 {
b368969c 1724 pRequest->getFieldAsString(VID_CLIENT_ADDRESS, m_workstation, 256);
91f6b72c
VK
1725 debugPrintf(5, _T("Real web client address is %s"), m_workstation);
1726 }
1727 }
1728
2a964810
VK
1729 if (pRequest->isFieldExist(VID_LANGUAGE))
1730 {
b368969c 1731 pRequest->getFieldAsString(VID_LANGUAGE, m_language, 8);
2a964810
VK
1732 }
1733
5039dede
AK
1734 if (!(m_dwFlags & CSF_AUTHENTICATED))
1735 {
d888bc1c 1736 UINT32 graceLogins = 0;
27858eaa 1737 bool closeOtherSessions = false;
b368969c
VK
1738 pRequest->getFieldAsString(VID_LOGIN_NAME, szLogin, MAX_USER_NAME);
1739 nAuthType = (int)pRequest->getFieldAsUInt16(VID_AUTH_TYPE);
958a9397 1740 debugPrintf(6, _T("authentication type %d"), nAuthType);
5039dede
AK
1741 switch(nAuthType)
1742 {
1743 case NETXMS_AUTH_TYPE_PASSWORD:
5ad55ecb 1744#ifdef UNICODE
b368969c 1745 pRequest->getFieldAsString(VID_PASSWORD, szPassword, 256);
5ad55ecb 1746#else
036d27a7 1747 pRequest->getFieldAsUtf8String(VID_PASSWORD, szPassword, 1024);
5ad55ecb 1748#endif
5039dede 1749 dwResult = AuthenticateUser(szLogin, szPassword, 0, NULL, NULL, &m_dwUserId,
27858eaa 1750 &m_dwSystemAccess, &changePasswd, &intruderLockout,
d888bc1c 1751 &closeOtherSessions, false, &graceLogins);
5039dede
AK
1752 break;
1753 case NETXMS_AUTH_TYPE_CERTIFICATE:
1754#ifdef _WITH_ENCRYPTION
1755 pCert = CertificateFromLoginMessage(pRequest);
1756 if (pCert != NULL)
1757 {
1758 BYTE signature[256];
967893bb 1759 UINT32 dwSigLen;
5039dede 1760
b368969c 1761 dwSigLen = pRequest->getFieldAsBinary(VID_SIGNATURE, signature, 256);
5039dede 1762 dwResult = AuthenticateUser(szLogin, (TCHAR *)signature, dwSigLen, pCert,
ab185583 1763 m_challenge, &m_dwUserId, &m_dwSystemAccess,
27858eaa 1764 &changePasswd, &intruderLockout,
d888bc1c 1765 &closeOtherSessions, false, &graceLogins);
5039dede
AK
1766 X509_free(pCert);
1767 }
1768 else
1769 {
1770 dwResult = RCC_BAD_CERTIFICATE;
1771 }
1772#else
1773 dwResult = RCC_NOT_IMPLEMENTED;
1774#endif
1775 break;
958a9397
VK
1776 case NETXMS_AUTH_TYPE_SSO_TICKET:
1777 char ticket[1024];
b368969c 1778 pRequest->getFieldAsMBString(VID_PASSWORD, ticket, 1024);
958a9397
VK
1779 if (CASAuthenticate(ticket, szLogin))
1780 {
1781 debugPrintf(5, _T("SSO ticket %hs is valid, login name %s"), ticket, szLogin);
1782 dwResult = AuthenticateUser(szLogin, NULL, 0, NULL, NULL, &m_dwUserId,
27858eaa 1783 &m_dwSystemAccess, &changePasswd, &intruderLockout,
d888bc1c 1784 &closeOtherSessions, true, &graceLogins);
958a9397
VK
1785 }
1786 else
1787 {
1788 debugPrintf(5, _T("SSO ticket %hs is invalid"), ticket);
1789 dwResult = RCC_ACCESS_DENIED;
1790 }
1791 break;
5039dede
AK
1792 default:
1793 dwResult = RCC_UNSUPPORTED_AUTH_TYPE;
1794 break;
1795 }
1796
1a1d02af
VK
1797 // Additional validation by loaded modules
1798 if (dwResult == RCC_SUCCESS)
1799 {
1800 for(UINT32 i = 0; i < g_dwNumModules; i++)
1801 {
1802 if (g_pModuleList[i].pfAdditionalLoginCheck != NULL)
1803 {
1804 dwResult = g_pModuleList[i].pfAdditionalLoginCheck(m_dwUserId, pRequest);
1805 if (dwResult != RCC_SUCCESS)
1806 {
1807 debugPrintf(4, _T("Login blocked by module %s (rcc=%d)"), g_pModuleList[i].szName, dwResult);
1808 break;
1809 }
1810 }
1811 }
1812 }
1813
5039dede
AK
1814 if (dwResult == RCC_SUCCESS)
1815 {
1816 m_dwFlags |= CSF_AUTHENTICATED;
77a08c86
VK
1817 nx_strncpy(m_loginName, szLogin, MAX_USER_NAME);
1818 _sntprintf(m_sessionName, MAX_SESSION_NAME, _T("%s@%s"), szLogin, m_workstation);
a51628e2 1819 m_loginTime = time(NULL);
b368969c
VK
1820 msg.setField(VID_RCC, RCC_SUCCESS);
1821 msg.setField(VID_USER_SYS_RIGHTS, m_dwSystemAccess);
1822 msg.setField(VID_USER_ID, m_dwUserId);
1823 msg.setField(VID_SESSION_ID, (UINT32)m_id);
1824 msg.setField(VID_CHANGE_PASSWD_FLAG, (WORD)changePasswd);
1825 msg.setField(VID_DBCONN_STATUS, (UINT16)((g_flags & AF_DB_CONNECTION_LOST) ? 0 : 1));
1826 msg.setField(VID_ZONING_ENABLED, (UINT16)((g_flags & AF_ENABLE_ZONING) ? 1 : 0));
90e3031f
VK
1827 msg.setField(VID_POLLING_INTERVAL, (INT32)DCObject::m_defaultPollingInterval);
1828 msg.setField(VID_RETENTION_TIME, (INT32)DCObject::m_defaultRetentionTime);
b368969c
VK
1829 msg.setField(VID_ALARM_STATUS_FLOW_STATE, (UINT16)ConfigReadInt(_T("StrictAlarmStatusFlow"), 0));
1830 msg.setField(VID_TIMED_ALARM_ACK_ENABLED, (UINT16)ConfigReadInt(_T("EnableTimedAlarmAck"), 0));
1831 msg.setField(VID_VIEW_REFRESH_INTERVAL, (UINT16)ConfigReadInt(_T("MinViewRefreshInterval"), 200));
1832 msg.setField(VID_HELPDESK_LINK_ACTIVE, (UINT16)((g_flags & AF_HELPDESK_LINK_ACTIVE) ? 1 : 0));
1833 msg.setField(VID_ALARM_LIST_DISP_LIMIT, ConfigReadULong(_T("AlarmListDisplayLimit"), 4096));
88072662 1834 msg.setField(VID_SERVER_COMMAND_TIMEOUT, ConfigReadULong(_T("ServerCommandOutputTimeout"), 60));
d888bc1c 1835 msg.setField(VID_GRACE_LOGINS, graceLogins);
88072662 1836
4970ef34
VK
1837 if (pRequest->getFieldAsBoolean(VID_ENABLE_COMPRESSION))
1838 {
1839 debugPrintf(3, _T("Protocol level compression is supported by client"));
1840 m_dwFlags |= CSF_COMPRESSION_ENABLED;
1841 msg.setField(VID_ENABLE_COMPRESSION, true);
1842 }
1843 else
1844 {
1845 debugPrintf(3, _T("Protocol level compression is not supported by client"));
1846 }
1847
88072662
VK
1848 TCHAR buffer[MAX_DB_STRING];
1849 ConfigReadStr(_T("ServerName"), buffer, MAX_DB_STRING, _T(""));
1850 msg.setField(VID_SERVER_NAME, buffer);
1851
1852 ConfigReadStr(_T("ServerColor"), buffer, MAX_DB_STRING, _T(""));
1853 msg.setField(VID_SERVER_COLOR, buffer);
1854
8b75662b
EJ
1855 ConfigReadStr(_T("MessageOfTheDay"), buffer, MAX_DB_STRING, _T(""));
1856 msg.setField(VID_MESSAGE_OF_THE_DAY, buffer);
1857
77a08c86 1858 debugPrintf(3, _T("User %s authenticated (language=%s clientInfo=\"%s\")"), m_sessionName, m_language, m_clientInfo);
0d402aa8 1859 writeAuditLog(AUDIT_SECURITY, true, 0, _T("User \"%s\" logged in (language: %s; client info: %s)"), szLogin, m_language, m_clientInfo);
27858eaa
VK
1860
1861 if (closeOtherSessions)
1862 {
1863 debugPrintf(5, _T("Closing other sessions for user %s"), m_loginName);
1864 CloseOtherSessions(m_dwUserId, m_id);
1865 }
5039dede
AK
1866 }
1867 else
1868 {
b368969c 1869 msg.setField(VID_RCC, dwResult);
0d402aa8 1870 writeAuditLog(AUDIT_SECURITY, false, 0,
5039dede 1871 _T("User \"%s\" login failed with error code %d (client info: %s)"),
77a08c86 1872 szLogin, dwResult, m_clientInfo);
ab185583
VK
1873 if (intruderLockout)
1874 {
0d402aa8 1875 writeAuditLog(AUDIT_SECURITY, false, 0,
ab185583
VK
1876 _T("User account \"%s\" temporary disabled due to excess count of failed authentication attempts"), szLogin);
1877 }
ea887770 1878 m_dwUserId = INVALID_INDEX; // reset user ID to avoid incorrect count of logged in sessions for that user
5039dede
AK
1879 }
1880 }
1881 else
1882 {
b368969c 1883 msg.setField(VID_RCC, RCC_OUT_OF_STATE_REQUEST);
5039dede
AK
1884 }
1885
1886 // Send response
e05b1945 1887 sendMessage(&msg);
5039dede
AK
1888}
1889
6a6b96c0
EJ
1890/**
1891 * Send alarm categories to client
1892*/
a881eafa 1893void ClientSession::getAlarmCategories(UINT32 requestId)
6a6b96c0
EJ
1894{
1895 NXCPMessage msg;
1896
1897 // Prepare response message
1898 msg.setCode(CMD_REQUEST_COMPLETED);
a881eafa 1899 msg.setId(requestId);
6a6b96c0
EJ
1900
1901 // Check access rights
1902 if (checkSysAccessRights(SYSTEM_ACCESS_EPP))
1903 {
a881eafa
VK
1904 GetAlarmCategories(&msg);
1905 msg.setField(VID_RCC, RCC_SUCCESS);
6a6b96c0
EJ
1906 }
1907 else
1908 {
1909 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
1910 }
1911 sendMessage(&msg);
1912}
1913
1914/**
1915* Update alarm category
1916*/
1917void ClientSession::modifyAlarmCategory(NXCPMessage *pRequest)
1918{
1919 NXCPMessage msg;
6a6b96c0
EJ
1920 msg.setCode(CMD_REQUEST_COMPLETED);
1921 msg.setId(pRequest->getId());
1922
1923 // Check access rights
1924 if (checkSysAccessRights(SYSTEM_ACCESS_EPP))
1925 {
f5050daf
EJ
1926 UINT32 id = 0;
1927 msg.setField(VID_RCC, UpdateAlarmCategory(pRequest, &id));
1928 msg.setField(VID_CATEGORY_ID, id);
6a6b96c0
EJ
1929 }
1930 else
1931 {
1932 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
1933 }
1934
1935 // Send response
1936 sendMessage(&msg);
1937}
1938
1939/**
1940* Delete alarm category
1941*/
a881eafa 1942void ClientSession::deleteAlarmCategory(NXCPMessage *request)
6a6b96c0
EJ
1943{
1944 NXCPMessage msg;
6a6b96c0 1945 msg.setCode(CMD_REQUEST_COMPLETED);
a881eafa 1946 msg.setId(request->getId());
6a6b96c0
EJ
1947
1948 // Check access rights
1949 if (checkSysAccessRights(SYSTEM_ACCESS_EPP))
1950 {
a881eafa
VK
1951 UINT32 categoryId = request->getFieldAsInt32(VID_CATEGORY_ID);
1952 if (!g_pEventPolicy->isCategoryInUse(categoryId))
6a6b96c0 1953 {
a881eafa 1954 msg.setField(VID_RCC, DeleteAlarmCategory(categoryId));
6a6b96c0
EJ
1955 }
1956 else
1957 {
1958 msg.setField(VID_RCC, RCC_CATEGORY_IN_USE);
1959 }
1960 }
1961 else
1962 {
1963 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
1964 }
1965
1966 // Send response
1967 sendMessage(&msg);
1968}
1969
534e1b83
VK
1970/**
1971 * Send event configuration to client
1972 */
fbf8ec29 1973void ClientSession::sendEventDB(UINT32 dwRqId)
5039dede 1974{
b368969c 1975 NXCPMessage msg;
480e036b 1976 TCHAR szBuffer[4096];
5039dede
AK
1977
1978 // Prepare response message
b368969c 1979 msg.setCode(CMD_REQUEST_COMPLETED);
fbf8ec29 1980 msg.setId(dwRqId);
5039dede 1981
fcb03e65 1982 if (checkSysAccessRights(SYSTEM_ACCESS_VIEW_EVENT_DB) || checkSysAccessRights(SYSTEM_ACCESS_EDIT_EVENT_DB) || checkSysAccessRights(SYSTEM_ACCESS_EPP))
5039dede 1983 {
c8076b19 1984 if (!(g_flags & AF_DB_CONNECTION_LOST))
5039dede 1985 {
b368969c 1986 msg.setField(VID_RCC, RCC_SUCCESS);
fbf8ec29
EJ
1987 sendMessage(&msg);
1988 msg.deleteAllFields();
1989
1990 // Prepare data message
1991 msg.setCode(CMD_EVENT_DB_RECORD);
1992 msg.setId(dwRqId);
1993
1994 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
1995 DB_UNBUFFERED_RESULT hResult = DBSelectUnbuffered(hdb, _T("SELECT event_code,event_name,severity,flags,message,description FROM event_cfg"));
1996 if (hResult != NULL)
1997 {
1998 while(DBFetch(hResult))
1999 {
2000 msg.setField(VID_EVENT_CODE, DBGetFieldULong(hResult, 0));
2001 msg.setField(VID_NAME, DBGetField(hResult, 1, szBuffer, 1024));
2002 msg.setField(VID_SEVERITY, DBGetFieldULong(hResult, 2));
2003 msg.setField(VID_FLAGS, DBGetFieldULong(hResult, 3));
2004
2005 DBGetField(hResult, 4, szBuffer, 4096);
2006 msg.setField(VID_MESSAGE, szBuffer);
2007
2008 DBGetField(hResult, 5, szBuffer, 4096);
2009 msg.setField(VID_DESCRIPTION, szBuffer);
2010
2011 sendMessage(&msg);
2012 msg.deleteAllFields();
2013 }
2014 DBFreeResult(hResult);
2015 }
2016 DBConnectionPoolReleaseConnection(hdb);
2017
2018 // End-of-list indicator
2019 msg.setField(VID_EVENT_CODE, (UINT32)0);
2020 msg.setEndOfSequence();
2021 }
2022 else
2023 {
2024 msg.setField(VID_RCC, RCC_DB_CONNECTION_LOST);
5039dede
AK
2025 }
2026 }
2027 else
fbf8ec29 2028 {
b368969c 2029 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
fbf8ec29 2030 }
e05b1945 2031 sendMessage(&msg);
5039dede
AK
2032}
2033
fbf8ec29
EJ
2034/**
2035 * Callback for sending event configuration change notifications
2036 */
2037static void SendEventDBChangeNotification(ClientSession *session, void *arg)
2038{
2039 if (session->isAuthenticated() &&
2040 (session->checkSysAccessRights(SYSTEM_ACCESS_VIEW_EVENT_DB) ||
2041 session->checkSysAccessRights(SYSTEM_ACCESS_EDIT_EVENT_DB) ||
2042 session->checkSysAccessRights(SYSTEM_ACCESS_EPP)))
2043 session->postMessage((NXCPMessage *)arg);
2044}
2045
480e036b
VK
2046/**
2047 * Update event template
2048 */
b368969c 2049void ClientSession::modifyEventTemplate(NXCPMessage *pRequest)
5039dede 2050{
b368969c 2051 NXCPMessage msg;
5039dede
AK
2052
2053 // Prepare reply message
b368969c
VK
2054 msg.setCode(CMD_REQUEST_COMPLETED);
2055 msg.setId(pRequest->getId());
fbf8ec29
EJ
2056
2057 UINT32 eventCode = pRequest->getFieldAsUInt32(VID_EVENT_CODE);
2058
8eb2d92b
VK
2059 // Check access rights
2060 if (checkSysAccessRights(SYSTEM_ACCESS_EDIT_EVENT_DB))
5039dede 2061 {
fbf8ec29
EJ
2062 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
2063
2064 bool bEventExist = IsDatabaseRecordExist(hdb, _T("event_cfg"), _T("event_code"), eventCode);
2065
2066 // Check that we are not trying to create event below 100000
2067 if (bEventExist || (eventCode >= FIRST_USER_EVENT_ID))
8eb2d92b 2068 {
fbf8ec29 2069 // Prepare and execute SQL query
305c4f0f
VK
2070 TCHAR name[MAX_EVENT_NAME];
2071 pRequest->getFieldAsString(VID_NAME, name, MAX_EVENT_NAME);
fbf8ec29
EJ
2072 if (IsValidObjectName(name, TRUE))
2073 {
2074 EventTemplate *evt = FindEventTemplateByCode(eventCode);
2075 json_t *oldValue = (evt != NULL) ? evt->toJson() : NULL;
2076
2077 DB_STATEMENT hStmt;
2078 if (bEventExist)
2079 {
2080 hStmt = DBPrepare(hdb, _T("UPDATE event_cfg SET event_name=?,severity=?,flags=?,message=?,description=? WHERE event_code=?"));
2081 }
2082 else
2083 {
2084 hStmt = DBPrepare(hdb, _T("INSERT INTO event_cfg (event_name,severity,flags,message,description,event_code,guid) VALUES (?,?,?,?,?,?,?)"));
2085 }
2086
2087 if (hStmt != NULL)
2088 {
2089 DBBind(hStmt, 1, DB_SQLTYPE_VARCHAR, name, DB_BIND_STATIC);
2090 DBBind(hStmt, 2, DB_SQLTYPE_INTEGER, pRequest->getFieldAsInt32(VID_SEVERITY));
2091 DBBind(hStmt, 3, DB_SQLTYPE_INTEGER, pRequest->getFieldAsInt32(VID_FLAGS));
2092 DBBind(hStmt, 4, DB_SQLTYPE_VARCHAR, pRequest->getFieldAsString(VID_MESSAGE), DB_BIND_DYNAMIC, MAX_EVENT_MSG_LENGTH - 1);
2093 DBBind(hStmt, 5, DB_SQLTYPE_TEXT, pRequest->getFieldAsString(VID_DESCRIPTION), DB_BIND_DYNAMIC);
2094 DBBind(hStmt, 6, DB_SQLTYPE_INTEGER, eventCode);
2095 if (!bEventExist)
2096 {
2097 DBBind(hStmt, 7, DB_SQLTYPE_VARCHAR, uuid::generate());
2098 }
2099
2100 if (DBExecute(hStmt))
2101 {
2102 msg.setField(VID_RCC, RCC_SUCCESS);
2103 ReloadEvents();
2104
2105 NXCPMessage nmsg(pRequest);
2106 nmsg.setCode(CMD_EVENT_DB_UPDATE);
2107 nmsg.setField(VID_NOTIFICATION_CODE, (WORD)NX_NOTIFY_ETMPL_CHANGED);
2108 EnumerateClientSessions(SendEventDBChangeNotification, &nmsg);
2109
2110 evt = FindEventTemplateByCode(eventCode);
2111 json_t *newValue = (evt != NULL) ? evt->toJson() : NULL;
2112 writeAuditLogWithValues(AUDIT_SYSCFG, true, 0, oldValue, newValue, _T("Event template %s [%d] modified"), name, eventCode);
2113 json_decref(newValue);
2114 }
2115 else
2116 {
2117 msg.setField(VID_RCC, RCC_DB_FAILURE);
2118 }
2119 DBFreeStatement(hStmt);
2120 }
2121 else
2122 {
2123 msg.setField(VID_RCC, RCC_DB_FAILURE);
2124 }
2125 json_decref(oldValue);
2126 }
2127 else
2128 {
2129 msg.setField(VID_RCC, RCC_INVALID_OBJECT_NAME);
2130 }
2131 }
2132 else
2133 {
2134 msg.setField(VID_RCC, RCC_INVALID_EVENT_CODE);
5039dede 2135 }
fbf8ec29 2136 DBConnectionPoolReleaseConnection(hdb);
5039dede 2137 }
8eb2d92b
VK
2138 else
2139 {
b368969c 2140 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
fbf8ec29 2141 writeAuditLog(AUDIT_SYSCFG, false, 0, _T("Access denied on modify event template [%d]"), eventCode);
8eb2d92b 2142 }
5039dede
AK
2143
2144 // Send response
e05b1945 2145 sendMessage(&msg);
5039dede
AK
2146}
2147
480e036b
VK
2148/**
2149 * Delete event template
2150 */
b368969c 2151void ClientSession::deleteEventTemplate(NXCPMessage *pRequest)
5039dede 2152{
b368969c 2153 NXCPMessage msg;
967893bb 2154 UINT32 dwEventCode;
5039dede
AK
2155
2156 // Prepare reply message
b368969c
VK
2157 msg.setCode(CMD_REQUEST_COMPLETED);
2158 msg.setId(pRequest->getId());
5039dede 2159
b368969c 2160 dwEventCode = pRequest->getFieldAsUInt32(VID_EVENT_CODE);
8eb2d92b
VK
2161
2162 // Check access rights
2163 if (checkSysAccessRights(SYSTEM_ACCESS_EDIT_EVENT_DB) && (dwEventCode >= FIRST_USER_EVENT_ID))
5039dede 2164 {
fbf8ec29
EJ
2165 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
2166 TCHAR szQuery[256];
2167 _sntprintf(szQuery, 256, _T("DELETE FROM event_cfg WHERE event_code=%d"), dwEventCode);
2168 if (DBQuery(hdb, szQuery))
2169 {
2170 DeleteEventTemplateFromList(dwEventCode);
dd62373c 2171
fbf8ec29
EJ
2172 NXCPMessage nmsg;
2173 nmsg.setCode(CMD_EVENT_DB_UPDATE);
2174 nmsg.setField(VID_NOTIFICATION_CODE, (WORD)NX_NOTIFY_ETMPL_DELETED);
2175 nmsg.setField(VID_EVENT_CODE, dwEventCode);
2176 EnumerateClientSessions(SendEventDBChangeNotification, &nmsg);
2177
2178 msg.setField(VID_RCC, RCC_SUCCESS);
2179
2180 writeAuditLog(AUDIT_SYSCFG, true, 0, _T("Event template [%d] deleted"), dwEventCode);
2181 }
2182 else
2183 {
2184 msg.setField(VID_RCC, RCC_DB_FAILURE);
2185 }
2186 DBConnectionPoolReleaseConnection(hdb);
5039dede 2187 }
8eb2d92b
VK
2188 else
2189 {
b368969c 2190 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
0d402aa8 2191 writeAuditLog(AUDIT_SYSCFG, false, 0, _T("Access denied on delete event template [%d]"), dwEventCode);
8eb2d92b 2192 }
5039dede
AK
2193
2194 // Send response
e05b1945 2195 sendMessage(&msg);
5039dede
AK
2196}
2197
480e036b
VK
2198/**
2199 * Generate event code for new event template
2200 */
967893bb 2201void ClientSession::generateEventCode(UINT32 dwRqId)
5039dede 2202{
b368969c 2203 NXCPMessage msg;
5039dede
AK
2204
2205 // Prepare reply message
b368969c
VK
2206 msg.setCode(CMD_REQUEST_COMPLETED);
2207 msg.setId(dwRqId);
5039dede 2208
8eb2d92b
VK
2209 // Check access rights
2210 if (checkSysAccessRights(SYSTEM_ACCESS_EDIT_EVENT_DB))
5039dede 2211 {
b368969c 2212 msg.setField(VID_EVENT_CODE, CreateUniqueId(IDG_EVENT));
5039dede
AK
2213 }
2214 else
2215 {
b368969c 2216 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
5039dede
AK
2217 }
2218
2219 // Send response
e05b1945 2220 sendMessage(&msg);
5039dede
AK
2221}
2222
22f38627
VK
2223/**
2224 * Data for session object filter
2225 */
2226struct SessionObjectFilterData
2227{
2228 ClientSession *session;
2229 time_t baseTimeStamp;
2230};
2231
2232/**
2233 * Object filter for ClientSession::sendAllObjects
2234 */
2235static bool SessionObjectFilter(NetObj *object, void *data)
2236{
2237 return !object->isHidden() && !object->isSystem() && !object->isDeleted() &&
2238 (object->getTimeStamp() >= ((SessionObjectFilterData *)data)->baseTimeStamp) &&
2239 object->checkAccessRights(((SessionObjectFilterData *)data)->session->getUserId(), OBJECT_ACCESS_READ);
2240}
2241
6b8e9f96
VK
2242/**
2243 * Send all objects to client
2244 */
b368969c 2245void ClientSession::sendAllObjects(NXCPMessage *pRequest)
5039dede 2246{
b368969c 2247 NXCPMessage msg;
5039dede
AK
2248
2249 // Send confirmation message
b368969c
VK
2250 msg.setCode(CMD_REQUEST_COMPLETED);
2251 msg.setId(pRequest->getId());
2252 msg.setField(VID_RCC, RCC_SUCCESS);
e05b1945 2253 sendMessage(&msg);
b368969c 2254 msg.deleteAllFields();
5039dede 2255
62768df3 2256 // Change "sync comments" flag
b368969c 2257 if (pRequest->getFieldAsUInt16(VID_SYNC_COMMENTS))
5039dede
AK
2258 m_dwFlags |= CSF_SYNC_OBJECT_COMMENTS;
2259 else
2260 m_dwFlags &= ~CSF_SYNC_OBJECT_COMMENTS;
2261
5039dede 2262 // Prepare message
b368969c 2263 msg.setCode(CMD_OBJECT);
5039dede
AK
2264
2265 // Send objects, one per message
22f38627
VK
2266 SessionObjectFilterData data;
2267 data.session = this;
2268 data.baseTimeStamp = pRequest->getFieldAsTime(VID_TIMESTAMP);
2269 ObjectArray<NetObj> *objects = g_idxObjectById.getObjects(true, SessionObjectFilter, &data);
c17f6cbc 2270 MutexLock(m_mutexSendObjects);
6aba3998
VK
2271 for(int i = 0; i < objects->size(); i++)
2272 {
2273 NetObj *object = objects->get(i);
22f38627
VK
2274 object->fillMessage(&msg);
2275 if (m_dwFlags & CSF_SYNC_OBJECT_COMMENTS)
2276 object->commentsToMessage(&msg);
2277 if (!object->checkAccessRights(m_dwUserId, OBJECT_ACCESS_MODIFY))
5039dede 2278 {
22f38627
VK
2279 // mask passwords
2280 msg.setField(VID_SHARED_SECRET, _T("********"));
2281 msg.setField(VID_SNMP_AUTH_PASSWORD, _T("********"));
2282 msg.setField(VID_SNMP_PRIV_PASSWORD, _T("********"));
5039dede 2283 }
22f38627
VK
2284 sendMessage(&msg);
2285 msg.deleteAllFields();
b16935d5 2286 object->decRefCount();
6aba3998
VK
2287 }
2288 delete objects;
5039dede
AK
2289
2290 // Send end of list notification
b368969c 2291 msg.setCode(CMD_OBJECT_LIST_END);
e05b1945 2292 sendMessage(&msg);
5039dede
AK
2293
2294 MutexUnlock(m_mutexSendObjects);
2295}
2296
6b8e9f96
VK
2297/**
2298 * Send selected objects to client
2299 */
b368969c 2300void ClientSession::sendSelectedObjects(NXCPMessage *pRequest)
62768df3 2301{
b368969c 2302 NXCPMessage msg;
62768df3
VK
2303
2304 // Send confirmation message
b368969c
VK
2305 msg.setCode(CMD_REQUEST_COMPLETED);
2306 msg.setId(pRequest->getId());
2307 msg.setField(VID_RCC, RCC_SUCCESS);
62768df3 2308 sendMessage(&msg);
b368969c 2309 msg.deleteAllFields();
62768df3
VK
2310
2311 // Change "sync comments" flag
0cd0d4af 2312 if (pRequest->getFieldAsBoolean(VID_SYNC_COMMENTS))
62768df3
VK
2313 m_dwFlags |= CSF_SYNC_OBJECT_COMMENTS;
2314 else
2315 m_dwFlags &= ~CSF_SYNC_OBJECT_COMMENTS;
2316
b368969c
VK
2317 UINT32 dwTimeStamp = pRequest->getFieldAsUInt32(VID_TIMESTAMP);
2318 UINT32 numObjects = pRequest->getFieldAsUInt32(VID_NUM_OBJECTS);
967893bb 2319 UINT32 *objects = (UINT32 *)malloc(sizeof(UINT32) * numObjects);
9a68ca24 2320 pRequest->getFieldAsInt32Array(VID_OBJECT_LIST, numObjects, objects);
b368969c 2321 UINT32 options = pRequest->getFieldAsUInt16(VID_FLAGS);
62768df3 2322
c17f6cbc 2323 MutexLock(m_mutexSendObjects);
62768df3
VK
2324
2325 // Prepare message
b368969c 2326 msg.setCode((options & OBJECT_SYNC_SEND_UPDATES) ? CMD_OBJECT_UPDATE : CMD_OBJECT);
62768df3
VK
2327
2328 // Send objects, one per message
967893bb 2329 for(UINT32 i = 0; i < numObjects; i++)
62768df3
VK
2330 {
2331 NetObj *object = FindObjectById(objects[i]);
7a4c94ee 2332 if ((object != NULL) &&
6b8e9f96
VK
2333 object->checkAccessRights(m_dwUserId, OBJECT_ACCESS_READ) &&
2334 (object->getTimeStamp() >= dwTimeStamp) &&
01152a54 2335 !object->isHidden() && !object->isSystem())
62768df3 2336 {
c42b4551 2337 object->fillMessage(&msg);
62768df3 2338 if (m_dwFlags & CSF_SYNC_OBJECT_COMMENTS)
6b8e9f96 2339 object->commentsToMessage(&msg);
456cb762
AK
2340 if (!object->checkAccessRights(m_dwUserId, OBJECT_ACCESS_MODIFY))
2341 {
2342 // mask passwords
b368969c
VK
2343 msg.setField(VID_SHARED_SECRET, _T("********"));
2344 msg.setField(VID_SNMP_AUTH_PASSWORD, _T("********"));
2345 msg.setField(VID_SNMP_PRIV_PASSWORD, _T("********"));
456cb762 2346 }
62768df3 2347 sendMessage(&msg);
b368969c 2348 msg.deleteAllFields();
62768df3
VK
2349 }
2350 }
2351
2352 MutexUnlock(m_mutexSendObjects);
2353 safe_free(objects);
9fc8ff38
VK
2354
2355 if (options & OBJECT_SYNC_DUAL_CONFIRM)
2356 {
b368969c
VK
2357 msg.setCode(CMD_REQUEST_COMPLETED);
2358 msg.setField(VID_RCC, RCC_SUCCESS);
9fc8ff38
VK
2359 sendMessage(&msg);
2360 }
62768df3
VK
2361}
2362
b1e9b6b3
VK
2363/**
2364 * Send all configuration variables to client
2365 */
c85c8ef2 2366void ClientSession::getConfigurationVariables(UINT32 dwRqId)
5039dede 2367{
967893bb 2368 UINT32 i, dwId, dwNumRecords;
b368969c 2369 NXCPMessage msg;
2589cc10 2370 TCHAR szBuffer[MAX_CONFIG_VALUE];
5039dede
AK
2371
2372 // Prepare message
b368969c
VK
2373 msg.setCode(CMD_REQUEST_COMPLETED);
2374 msg.setId(dwRqId);
5039dede
AK
2375
2376 // Check user rights
2377 if ((m_dwUserId == 0) || (m_dwSystemAccess & SYSTEM_ACCESS_SERVER_CONFIG))
2378 {
9bd1bace
VK
2379 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
2380
5039dede 2381 // Retrieve configuration variables from database
c7aa788e 2382 DB_RESULT hResult = DBSelect(hdb, _T("SELECT var_name,var_value,need_server_restart,data_type,description,default_value FROM config WHERE is_visible=1"));
5039dede
AK
2383 if (hResult != NULL)
2384 {
2385 // Send events, one per message
2386 dwNumRecords = DBGetNumRows(hResult);
b368969c 2387 msg.setField(VID_NUM_VARIABLES, dwNumRecords);
c7aa788e 2388 for(i = 0, dwId = VID_VARLIST_BASE; i < dwNumRecords; i++, dwId += 10)
5039dede 2389 {
c7aa788e
EJ
2390 msg.setField(dwId, DBGetField(hResult, i, 0, szBuffer, MAX_DB_STRING));
2391 msg.setField(dwId + 1, DBGetField(hResult, i, 1, szBuffer, MAX_CONFIG_VALUE));
2392 msg.setField(dwId + 2, (WORD)DBGetFieldLong(hResult, i, 2));
2393 msg.setField(dwId + 3, DBGetField(hResult, i, 3, szBuffer, MAX_CONFIG_VALUE));
2394 msg.setField(dwId + 4, DBGetField(hResult, i, 4, szBuffer, MAX_CONFIG_VALUE));
2395 msg.setField(dwId + 5, DBGetField(hResult, i, 5, szBuffer, MAX_CONFIG_VALUE));
e11eade2
EJ
2396 }
2397 DBFreeResult(hResult);
d6fec35c
VK
2398
2399 hResult = DBSelect(hdb, _T("SELECT var_name,var_value,var_description FROM config_values"));
2400 if (hResult != NULL)
e11eade2 2401 {
d6fec35c
VK
2402 dwNumRecords = DBGetNumRows(hResult);
2403 msg.setField(VID_NUM_VALUES, dwNumRecords);
2404 for(i = 0; i < dwNumRecords; i++)
2405 {
2406 msg.setField(dwId++, DBGetField(hResult, i, 0, szBuffer, MAX_DB_STRING));
2407 msg.setField(dwId++, DBGetField(hResult, i, 1, szBuffer, MAX_CONFIG_VALUE));
2408 msg.setField(dwId++, DBGetField(hResult, i, 2, szBuffer, MAX_DB_STRING));
2409 }
2410 DBFreeResult(hResult);
2411
2412 msg.setField(VID_RCC, RCC_SUCCESS);
2413 }
2414 else
2415 {
2416 msg.setField(VID_RCC, RCC_DB_FAILURE);
5039dede 2417 }
d6fec35c
VK
2418 }
2419 else
2420 {
2421 msg.setField(VID_RCC, RCC_DB_FAILURE);
5039dede 2422 }
9bd1bace 2423 DBConnectionPoolReleaseConnection(hdb);
5039dede
AK
2424 }
2425 else
2426 {
b368969c 2427 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
5039dede
AK
2428 }
2429
2430 // Send response
e05b1945 2431 sendMessage(&msg);
5039dede
AK
2432}
2433
c85c8ef2
VK
2434/**
2435 * Get public configuration variable by name
2436 */
2437void ClientSession::getPublicConfigurationVariable(NXCPMessage *request)
2438{
2439 NXCPMessage msg;
2440 msg.setCode(CMD_REQUEST_COMPLETED);
2441 msg.setId(request->getId());
2442
2443 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
2444
2445 DB_STATEMENT hStmt = DBPrepare(hdb, _T("SELECT var_value FROM config WHERE var_name=? AND is_public='Y'"));
2446 if (hStmt != NULL)
2447 {
2448 TCHAR name[64];
2449 request->getFieldAsString(VID_NAME, name, 64);
2450 DBBind(hStmt, 1, DB_SQLTYPE_VARCHAR, name, DB_BIND_STATIC);
2451
2452 DB_RESULT hResult = DBSelectPrepared(hStmt);
2453 if (hResult != NULL)
2454 {
2455 if (DBGetNumRows(hResult) > 0)
2456 {
2589cc10 2457 TCHAR value[MAX_CONFIG_VALUE];
2458 msg.setField(VID_VALUE, DBGetField(hResult, 0, 0, value, MAX_CONFIG_VALUE));
c85c8ef2
VK
2459 msg.setField(VID_RCC, RCC_SUCCESS);
2460 }
2461 else
2462 {
2463 msg.setField(VID_RCC, RCC_UNKNOWN_CONFIG_VARIABLE);
2464 }
2465 DBFreeResult(hResult);
2466 }
2467 else
2468 {
2469 msg.setField(VID_RCC, RCC_DB_FAILURE);
2470 }
2471 DBFreeStatement(hStmt);
2472 }
2473 else
2474 {
2475 msg.setField(VID_RCC, RCC_DB_FAILURE);
2476 }
2d8d8ea2 2477
c85c8ef2
VK
2478 sendMessage(&msg);
2479}
2480
b1e9b6b3
VK
2481/**
2482 * Set configuration variable's value
2483 */
c85c8ef2 2484void ClientSession::setConfigurationVariable(NXCPMessage *pRequest)
5039dede 2485{
dbb49f94 2486 NXCPMessage msg(CMD_REQUEST_COMPLETED, pRequest->getId());
5039dede 2487
dbb49f94
VK
2488 TCHAR name[MAX_OBJECT_NAME];
2489 pRequest->getFieldAsString(VID_NAME, name, MAX_OBJECT_NAME);
5039dede 2490
5039dede
AK
2491 if ((m_dwUserId == 0) || (m_dwSystemAccess & SYSTEM_ACCESS_SERVER_CONFIG))
2492 {
dbb49f94
VK
2493 TCHAR oldValue[MAX_CONFIG_VALUE], newValue[MAX_CONFIG_VALUE];
2494 pRequest->getFieldAsString(VID_VALUE, newValue, MAX_CONFIG_VALUE);
2495 ConfigReadStr(name, oldValue, MAX_CONFIG_VALUE, _T(""));
2496 if (ConfigWriteStr(name, newValue, true))
c7aa788e 2497 {
b368969c 2498 msg.setField(VID_RCC, RCC_SUCCESS);
c7aa788e
EJ
2499 writeAuditLogWithValues(AUDIT_SYSCFG, true, 0, oldValue, newValue,
2500 _T("Server configuration variable \"%s\" changed from \"%s\" to \"%s\""), name, oldValue, newValue);
2501 }
5039dede 2502 else
c7aa788e 2503 {
b368969c 2504 msg.setField(VID_RCC, RCC_DB_FAILURE);
c7aa788e 2505 }
5039dede
AK
2506 }
2507 else
2508 {
dbb49f94 2509 writeAuditLog(AUDIT_SYSCFG, false, 0, _T("Access denied on setting server configuration variable \"%s\""), name);
b368969c 2510 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
5039dede
AK
2511 }
2512
2513 // Send response
e05b1945 2514 sendMessage(&msg);
5039dede
AK
2515}
2516
c7aa788e
EJ
2517/**
2518 * Set configuration variable's values to default
2519 */
2520void ClientSession::setDefaultConfigurationVariableValues(NXCPMessage *pRequest)
2521{
2522 NXCPMessage msg(CMD_REQUEST_COMPLETED, pRequest->getId());
2523 UINT32 rcc = RCC_SUCCESS;
2524
2525 if (checkSysAccessRights(SYSTEM_ACCESS_SERVER_CONFIG))
2526 {
2527 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
2528 DB_STATEMENT stmt = DBPrepare(hdb, _T("SELECT default_value FROM config WHERE var_name=?"));
2529 if (stmt != NULL)
2530 {
d390e5a8
VK
2531 int numVars = pRequest->getFieldAsInt32(VID_NUM_VARIABLES);
2532 UINT32 fieldId = VID_VARLIST_BASE;
c7aa788e
EJ
2533 TCHAR varName[64], defValue[MAX_CONFIG_VALUE];
2534 for(int i = 0; i < numVars; i++)
2535 {
d390e5a8 2536 pRequest->getFieldAsString(fieldId++, varName, 64);
c7aa788e
EJ
2537 DBBind(stmt, 1, DB_SQLTYPE_VARCHAR, varName, DB_BIND_STATIC);
2538
2539 DB_RESULT result = DBSelectPrepared(stmt);
2540 if (result != NULL)
2541 {
2542 DBGetField(result, 0, 0, defValue, MAX_CONFIG_VALUE);
2543 ConfigWriteStr(varName, defValue, false);
2544 }
2545 else
d390e5a8 2546 {
c7aa788e 2547 rcc = RCC_DB_FAILURE;
d390e5a8
VK
2548 break;
2549 }
c7aa788e
EJ
2550 }
2551 DBFreeStatement(stmt);
2552 }
2553 else
d390e5a8 2554 {
c7aa788e 2555 rcc = RCC_DB_FAILURE;
d390e5a8 2556 }
c7aa788e
EJ
2557 DBConnectionPoolReleaseConnection(hdb);
2558 }
2559 else
2560 {
2561 writeAuditLog(AUDIT_SYSCFG, false, 0, _T("Access denied for setting server configuration variables to default"));
2562 rcc = RCC_ACCESS_DENIED;
2563 }
2564 // Send response
2565 msg.setField(VID_RCC, rcc);
2566 sendMessage(&msg);
2567
2568}
2569
b1e9b6b3
VK
2570/**
2571 * Delete configuration variable
2572 */
c85c8ef2 2573void ClientSession::deleteConfigurationVariable(NXCPMessage *pRequest)
5039dede 2574{
dbb49f94 2575 NXCPMessage msg(CMD_REQUEST_COMPLETED, pRequest->getId());
5039dede 2576
dbb49f94
VK
2577 TCHAR name[MAX_OBJECT_NAME];
2578 pRequest->getFieldAsString(VID_NAME, name, MAX_OBJECT_NAME);
5039dede 2579
5039dede
AK
2580 if ((m_dwUserId == 0) || (m_dwSystemAccess & SYSTEM_ACCESS_SERVER_CONFIG))
2581 {
35959841 2582 if (ConfigDelete(name))
5039dede 2583 {
b368969c 2584 msg.setField(VID_RCC, RCC_SUCCESS);
dbb49f94 2585 writeAuditLog(AUDIT_SYSCFG, true, 0, _T("Server configuration variable \"%s\" deleted"), name);
5039dede
AK
2586 }
2587 else
2588 {
b368969c 2589 msg.setField(VID_RCC, RCC_DB_FAILURE);
5039dede
AK
2590 }
2591 }
2592 else
2593 {
dbb49f94 2594 writeAuditLog(AUDIT_SYSCFG, false, 0, _T("Access denied on delete server configuration variable \"%s\""), name);
b368969c 2595 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
5039dede
AK
2596 }
2597
2598 // Send response
e05b1945 2599 sendMessage(&msg);
5039dede
AK
2600}
2601
28229715
VK
2602/**
2603 * Set configuration clob
2604 */
b368969c 2605void ClientSession::setConfigCLOB(NXCPMessage *pRequest)
5039dede 2606{
dbb49f94 2607 NXCPMessage msg(CMD_REQUEST_COMPLETED, pRequest->getId());
7a4c94ee 2608
dbb49f94
VK
2609 TCHAR name[MAX_OBJECT_NAME];
2610 pRequest->getFieldAsString(VID_NAME, name, MAX_OBJECT_NAME);
5039dede
AK
2611 if (m_dwSystemAccess & SYSTEM_ACCESS_SERVER_CONFIG)
2612 {
dbb49f94
VK
2613 TCHAR *newValue = pRequest->getFieldAsString(VID_VALUE);
2614 if (newValue != NULL)
5039dede 2615 {
dbb49f94
VK
2616 TCHAR *oldValue = ConfigReadCLOB(name, _T(""));
2617 if (ConfigWriteCLOB(name, newValue, TRUE))
4d0c32f3 2618 {
b368969c 2619 msg.setField(VID_RCC, RCC_SUCCESS);
dbb49f94
VK
2620 writeAuditLogWithValues(AUDIT_SYSCFG, true, 0, oldValue, newValue,
2621 _T("Server configuration variable (long) \"%s\" changed"), name);
4d0c32f3
VK
2622 }
2623 else
2624 {
b368969c 2625 msg.setField(VID_RCC, RCC_DB_FAILURE);
4d0c32f3 2626 }
dbb49f94
VK
2627 free(oldValue);
2628 free(newValue);
5039dede
AK
2629 }
2630 else
2631 {
b368969c 2632 msg.setField(VID_RCC, RCC_INVALID_REQUEST);
5039dede
AK
2633 }
2634 }
2635 else
2636 {
dbb49f94 2637 writeAuditLog(AUDIT_SYSCFG, false, 0, _T("Access denied on setting server configuration variable \"%s\""), name);
b368969c 2638 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
5039dede 2639 }
7a4c94ee 2640
e05b1945 2641 sendMessage(&msg);
5039dede
AK
2642}
2643
b3eb058b
VK
2644/**
2645 * Get value of configuration clob
2646 */
b368969c 2647void ClientSession::getConfigCLOB(NXCPMessage *pRequest)
5039dede 2648{
b368969c 2649 NXCPMessage msg;
5039dede 2650 TCHAR name[MAX_OBJECT_NAME], *value;
7a4c94ee 2651
b368969c
VK
2652 msg.setId(pRequest->getId());
2653 msg.setCode(CMD_REQUEST_COMPLETED);
7a4c94ee 2654
5039dede
AK
2655 if (m_dwSystemAccess & SYSTEM_ACCESS_SERVER_CONFIG)
2656 {
b368969c 2657 pRequest->getFieldAsString(VID_NAME, name, MAX_OBJECT_NAME);
5039dede
AK
2658 value = ConfigReadCLOB(name, NULL);
2659 if (value != NULL)
2660 {
b368969c
VK
2661 msg.setField(VID_VALUE, value);
2662 msg.setField(VID_RCC, RCC_SUCCESS);
5039dede
AK
2663 free(value);
2664 }
2665 else
2666 {
b368969c 2667 msg.setField(VID_RCC, RCC_UNKNOWN_VARIABLE);
5039dede
AK
2668 }
2669 }
2670 else
2671 {
b368969c 2672 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
5039dede 2673 }
7a4c94ee 2674
e05b1945 2675 sendMessage(&msg);
5039dede
AK
2676}
2677
b3eb058b
VK
2678/**
2679 * Close session
2680 */
1da08bc6 2681void ClientSession::kill()
5039dede 2682{
5d9a9c84
VK
2683 notify(NX_NOTIFY_SESSION_KILLED);
2684
5039dede
AK
2685 // We shutdown socket connection, which will cause
2686 // read thread to stop, and other threads will follow
dbb49f94 2687 shutdown(m_hSocket, SHUT_RDWR);
5039dede
AK
2688}
2689
49fbe41f
VK
2690/**
2691 * Handler for new events
2692 */
e05b1945 2693void ClientSession::onNewEvent(Event *pEvent)
5039dede 2694{
c044d4f3 2695 if (isAuthenticated() && isSubscribedTo(NXC_CHANNEL_EVENTS) && (m_dwSystemAccess & SYSTEM_ACCESS_VIEW_EVENT_LOG))
5039dede 2696 {
1ff4448e 2697 NetObj *object = FindObjectById(pEvent->getSourceId());
2de8de66
VK
2698 // If can't find object - just send to all events, if object found send to thous who have rights
2699 if ((object == NULL) || object->checkAccessRights(m_dwUserId, OBJECT_ACCESS_READ))
1ff4448e 2700 {
2de8de66
VK
2701 NXCPMessage msg(CMD_EVENTLOG_RECORDS, 0);
2702 pEvent->prepareMessage(&msg);
2703 postMessage(&msg);
1ff4448e 2704 }
5039dede
AK
2705 }
2706}
2707
b784f8ac
VK
2708/**
2709 * Send object update (executed in thread pool)
2710 */
2711void ClientSession::sendObjectUpdate(NetObj *object)
2712{
2713 NXCPMessage msg(CMD_OBJECT_UPDATE, 0);
2714 if (!object->isDeleted())
2715 {
2716 object->fillMessage(&msg);
2717 if (m_dwFlags & CSF_SYNC_OBJECT_COMMENTS)
2718 object->commentsToMessage(&msg);
2719 }
2720 else
2721 {
2722 msg.setField(VID_OBJECT_ID, object->getId());
2723 msg.setField(VID_IS_DELETED, (UINT16)1);
2724 }
2725 MutexLock(m_mutexSendObjects);
2726 sendMessage(&msg);
2727 MutexUnlock(m_mutexSendObjects);
2728 object->decRefCount();
f55de0a9 2729 decRefCount();
b784f8ac
VK
2730}
2731
49fbe41f
VK
2732/**
2733 * Handler for object changes
2734 */
fffcff95 2735void ClientSession::onObjectChange(NetObj *object)
5039dede 2736{
b784f8ac
VK
2737 if (isAuthenticated() && isSubscribedTo(NXC_CHANNEL_OBJECTS) &&
2738 (object->isDeleted() || object->checkAccessRights(m_dwUserId, OBJECT_ACCESS_READ)))
2739 {
2740 object->incRefCount();
f55de0a9 2741 incRefCount();
b784f8ac
VK
2742 ThreadPoolExecute(g_mainThreadPool, this, &ClientSession::sendObjectUpdate, object);
2743 }
5039dede
AK
2744}
2745
b1e9b6b3
VK
2746/**
2747 * Send notification message to server
2748 */
967893bb 2749void ClientSession::notify(UINT32 dwCode, UINT32 dwData)
5039dede 2750{
b368969c 2751 NXCPMessage msg;
5039dede 2752
b368969c
VK
2753 msg.setCode(CMD_NOTIFY);
2754 msg.setField(VID_NOTIFICATION_CODE, dwCode);
2755 msg.setField(VID_NOTIFICATION_DATA, dwData);
d8fa3917 2756 postMessage(&msg);
5039dede
AK
2757}
2758
d8fa3917
VK
2759/**
2760 * Set information about conflicting nodes to VID_VALUE field
2761 */
a191c634 2762static void SetNodesConflictString(NXCPMessage *msg, UINT32 zoneUIN, InetAddress ipAddr)
b69af14b 2763{
d8fa3917
VK
2764 if (!ipAddr.isValid())
2765 return;
b69af14b 2766
a191c634
VK
2767 Node *sameNode = FindNodeByIP(zoneUIN, ipAddr);
2768 Subnet *sameSubnet = FindSubnetByIP(zoneUIN, ipAddr);
d8fa3917
VK
2769 if (sameNode != NULL)
2770 {
2771 msg->setField(VID_VALUE, sameNode->getName());
2772 }
2773 else if (sameSubnet != NULL)
2774 {
2775 msg->setField(VID_VALUE, sameSubnet->getName());
2776 }
2777 else
2778 {
2779 msg->setField(VID_VALUE, _T(""));
b69af14b 2780 }
2781}
2782
b1e9b6b3
VK
2783/**
2784 * Modify object
2785 */
b368969c 2786void ClientSession::modifyObject(NXCPMessage *pRequest)
5039dede 2787{
967893bb 2788 UINT32 dwObjectId, dwResult = RCC_SUCCESS;
fffcff95 2789 NetObj *object;
b368969c 2790 NXCPMessage msg;
5039dede
AK
2791
2792 // Prepare reply message
b368969c
VK
2793 msg.setCode(CMD_REQUEST_COMPLETED);
2794 msg.setId(pRequest->getId());
5039dede 2795
b368969c 2796 dwObjectId = pRequest->getFieldAsUInt32(VID_OBJECT_ID);
fffcff95
VK
2797 object = FindObjectById(dwObjectId);
2798 if (object != NULL)
5039dede 2799 {
fffcff95 2800 if (object->checkAccessRights(m_dwUserId, OBJECT_ACCESS_MODIFY))
5039dede 2801 {
6336bba3
VK
2802 json_t *oldValue = object->toJson();
2803
5039dede
AK
2804 // If user attempts to change object's ACL, check
2805 // if he has OBJECT_ACCESS_ACL permission
5c44534b 2806 if (pRequest->isFieldExist(VID_ACL_SIZE))
fffcff95 2807 if (!object->checkAccessRights(m_dwUserId, OBJECT_ACCESS_ACL))
5039dede
AK
2808 dwResult = RCC_ACCESS_DENIED;
2809
5d7681cc 2810 // If user attempts to rename object, check object's name
5c44534b 2811 if (pRequest->isFieldExist(VID_OBJECT_NAME))
5d7681cc
VK
2812 {
2813 TCHAR name[256];
b368969c 2814 pRequest->getFieldAsString(VID_OBJECT_NAME, name, 256);
5d7681cc
VK
2815 if (!IsValidObjectName(name, TRUE))
2816 dwResult = RCC_INVALID_OBJECT_NAME;
2817 }
2818
5039dede 2819 // If allowed, change object and set completion code
5d7681cc 2820 if (dwResult == RCC_SUCCESS)
6ff21d27 2821 {
c42b4551 2822 dwResult = object->modifyFromMessage(pRequest);
6ff21d27
VK
2823 if (dwResult == RCC_SUCCESS)
2824 {
fffcff95 2825 object->postModify();
6ff21d27 2826 }
b69af14b 2827 else if (dwResult == RCC_ALREADY_EXIST)
2828 {
d8fa3917 2829 // Add information about conflicting nodes
b69af14b 2830 InetAddress ipAddr;
2831
2832 if (pRequest->isFieldExist(VID_IP_ADDRESS))
2833 {
2834 ipAddr = pRequest->getFieldAsInetAddress(VID_IP_ADDRESS);
2835 } else if (pRequest->isFieldExist(VID_PRIMARY_NAME))
2836 {
2837 TCHAR primaryName[MAX_DNS_NAME];
2838 pRequest->getFieldAsString(VID_PRIMARY_NAME, primaryName, MAX_DNS_NAME);
2839 ipAddr = InetAddress::resolveHostName(primaryName);
2840 }
a191c634 2841 SetNodesConflictString(&msg, ((Node*)object)->getZoneUIN(), ipAddr);
b69af14b 2842 }
6ff21d27 2843 }
b368969c 2844 msg.setField(VID_RCC, dwResult);
5039dede
AK
2845
2846 if (dwResult == RCC_SUCCESS)
2847 {
6336bba3
VK
2848 json_t *newValue = object->toJson();
2849 writeAuditLogWithValues(AUDIT_OBJECTS, true, dwObjectId, oldValue, newValue,
2850 _T("Object %s modified from client"), object->getName());
2851 json_decref(newValue);
5039dede 2852 }
6336bba3 2853 json_decref(oldValue);
5039dede
AK
2854 }
2855 else
2856 {
b368969c 2857 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
6336bba3 2858 writeAuditLog(AUDIT_OBJECTS, false, dwObjectId, _T("Access denied on object modification"));
5039dede
AK
2859 }
2860 }
2861 else
2862 {
b368969c 2863 msg.setField(VID_RCC, RCC_INVALID_OBJECT_ID);
5039dede
AK
2864 }
2865
2866 // Send response
e05b1945 2867 sendMessage(&msg);
5039dede
AK
2868}
2869
b1e9b6b3
VK
2870/**
2871 * Send users database to client
2872 */
967893bb 2873void ClientSession::sendUserDB(UINT32 dwRqId)
5039dede 2874{
b368969c 2875 NXCPMessage msg;
b368969c
VK
2876 msg.setCode(CMD_REQUEST_COMPLETED);
2877 msg.setId(dwRqId);
2878 msg.setField(VID_RCC, RCC_SUCCESS);
e05b1945 2879 sendMessage(&msg);
b368969c 2880 msg.deleteAllFields();
5039dede 2881
a50eaebe 2882 // Send user database
e2579e2e
VK
2883 Iterator<UserDatabaseObject> *users = OpenUserDatabase();
2884 while(users->hasNext())
5039dede 2885 {
e2579e2e
VK
2886 UserDatabaseObject *object = users->next();
2887 msg.setCode(object->isGroup() ? CMD_GROUP_DATA : CMD_USER_DATA);
2888 object->fillMessage(&msg);
e05b1945 2889 sendMessage(&msg);
b368969c 2890 msg.deleteAllFields();
5039dede 2891 }
e2579e2e 2892 CloseUserDatabase(users);
5039dede
AK
2893
2894 // Send end-of-database notification
b368969c 2895 msg.setCode(CMD_USER_DB_EOF);
e05b1945 2896 sendMessage(&msg);
5039dede
AK
2897}
2898
b1e9b6b3
VK
2899/**
2900 * Create new user
2901 */
b368969c 2902void ClientSession::createUser(NXCPMessage *pRequest)
5039dede 2903{
b368969c 2904 NXCPMessage msg;
5039dede
AK
2905
2906 // Prepare response message
b368969c
VK
2907 msg.setCode(CMD_REQUEST_COMPLETED);
2908 msg.setId(pRequest->getId());
5039dede
AK
2909
2910 // Check user rights
2911 if (!(m_dwSystemAccess & SYSTEM_ACCESS_MANAGE_USERS))
2912 {
b368969c 2913 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
5039dede
AK
2914 }
2915 else if (!(m_dwFlags & CSF_USER_DB_LOCKED))
2916 {
2917 // User database have to be locked before any
2918 // changes to user database can be made
b368969c 2919 msg.setField(VID_RCC, RCC_OUT_OF_STATE_REQUEST);
5039dede
AK
2920 }
2921 else
2922 {
967893bb 2923 UINT32 dwResult, dwUserId;
35f836fe 2924 TCHAR szUserName[MAX_USER_NAME];
5039dede 2925
b368969c 2926 pRequest->getFieldAsString(VID_USER_NAME, szUserName, MAX_USER_NAME);
5039dede
AK
2927 if (IsValidObjectName(szUserName))
2928 {
84ea7692
VK
2929 bool isGroup = pRequest->getFieldAsBoolean(VID_IS_GROUP);
2930 dwResult = CreateNewUser(szUserName, isGroup, &dwUserId);
b368969c 2931 msg.setField(VID_RCC, dwResult);
5039dede 2932 if (dwResult == RCC_SUCCESS)
0a710f23 2933 {
b368969c 2934 msg.setField(VID_USER_ID, dwUserId); // Send id of new user to client
88e14cac 2935 writeAuditLog(AUDIT_SECURITY, true, 0, _T("%s %s created"), isGroup ? _T("Group") : _T("User"), szUserName);
0a710f23 2936 }
5039dede
AK
2937 }
2938 else
2939 {
b368969c 2940 msg.setField(VID_RCC, RCC_INVALID_OBJECT_NAME);
5039dede
AK
2941 }
2942 }
2943
2944 // Send response
e05b1945 2945 sendMessage(&msg);
5039dede
AK
2946}
2947
b1e9b6b3
VK
2948/**
2949 * Update existing user's data
2950 */
b368969c 2951void ClientSession::updateUser(NXCPMessage *pRequest)
5039dede 2952{
b368969c 2953 NXCPMessage msg;
5039dede
AK
2954
2955 // Prepare response message
b368969c
VK
2956 msg.setCode(CMD_REQUEST_COMPLETED);
2957 msg.setId(pRequest->getId());
5039dede
AK
2958
2959 // Check user rights
2960 if (!(m_dwSystemAccess & SYSTEM_ACCESS_MANAGE_USERS))
2961 {
b368969c 2962 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
5039dede
AK
2963 }
2964 else if (!(m_dwFlags & CSF_USER_DB_LOCKED))
2965 {
2966 // User database have to be locked before any
2967 // changes to user database can be made
b368969c 2968 msg.setField(VID_RCC, RCC_OUT_OF_STATE_REQUEST);
5039dede
AK
2969 }
2970 else
2971 {
0f42cad1
VK
2972 json_t *oldData = NULL, *newData = NULL;
2973 UINT32 result = ModifyUserDatabaseObject(pRequest, &oldData, &newData);
0a710f23
VK
2974 if (result == RCC_SUCCESS)
2975 {
2976 TCHAR name[MAX_DB_STRING];
b368969c 2977 UINT32 id = pRequest->getFieldAsUInt32(VID_USER_ID);
0a710f23 2978 ResolveUserId(id, name, MAX_DB_STRING);
0f42cad1 2979 writeAuditLogWithValues(AUDIT_SECURITY, true, 0, oldData, newData,
0a710f23
VK
2980 _T("%s %s modified"), (id & GROUP_FLAG) ? _T("Group") : _T("User"), name);
2981 }
b368969c 2982 msg.setField(VID_RCC, result);
0f42cad1
VK
2983 json_decref(oldData);
2984 json_decref(newData);
5039dede
AK
2985 }
2986
2987 // Send response
e05b1945 2988 sendMessage(&msg);
5039dede
AK
2989}
2990
2d8d8ea2 2991/**
2992 * Delete user
2993 */
2994void ClientSession::detachLdapUser(NXCPMessage *pRequest)
2995{
2996 NXCPMessage msg;
2997
2998 // Prepare response message
2999 msg.setCode(CMD_REQUEST_COMPLETED);
3000 msg.setId(pRequest->getId());
3001 UINT32 id = pRequest->getFieldAsUInt32(VID_USER_ID);
3002
3003 // Check user rights
3004 if (!(m_dwSystemAccess & SYSTEM_ACCESS_MANAGE_USERS))
3005 {
3006 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
3007 }
3008 else if (!(m_dwFlags & CSF_USER_DB_LOCKED))
3009 {
3010 // User database have to be locked before any
3011 // changes to user database can be made
3012 msg.setField(VID_RCC, RCC_OUT_OF_STATE_REQUEST);
3013 }
3014 else
3015 {
3016 UINT32 result = DetachLdapUser(id);
3017 if (result == RCC_SUCCESS)
3018 {
3019 TCHAR name[MAX_DB_STRING];
3020 ResolveUserId(id, name, MAX_DB_STRING);
88e14cac
VK
3021 writeAuditLog(AUDIT_SECURITY, true, 0,
3022 _T("%s %s detached from LDAP account"), (id & GROUP_FLAG) ? _T("Group") : _T("User"), name);
2d8d8ea2 3023 }
3024 msg.setField(VID_RCC, result);
3025 }
3026
3027 // Send response
3028 sendMessage(&msg);
3029}
3030
b1e9b6b3
VK
3031/**
3032 * Delete user
3033 */
b368969c 3034void ClientSession::deleteUser(NXCPMessage *pRequest)
5039dede 3035{
b368969c 3036 NXCPMessage msg;
967893bb 3037 UINT32 dwUserId;
5039dede
AK
3038
3039 // Prepare response message
b368969c
VK
3040 msg.setCode(CMD_REQUEST_COMPLETED);
3041 msg.setId(pRequest->getId());
5039dede
AK
3042