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