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