String class refactored; background log writer option implemented; fixed incorrect...
[public/netxms.git] / src / server / core / session.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** Copyright (C) 2003-2014 Raden Solutions
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"
24 #include <netxms_mt.h>
25 #include <nxtools.h>
26
27 #ifdef _WIN32
28 #include <psapi.h>
29 #define write _write
30 #define close _close
31 #else
32 #include <dirent.h>
33 #endif
34
35 #ifndef min
36 #define min(a,b) ((a) < (b) ? (a) : (b))
37 #endif
38
39 #ifndef S_ISREG
40 #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
41 #endif
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
53 /**
54 * Constants
55 */
56 #define TRAP_CREATE 1
57 #define TRAP_UPDATE 2
58 #define TRAP_DELETE 3
59
60 #define MAX_MSG_SIZE 4194304
61
62 /**
63 * Externals
64 */
65 extern Queue g_statusPollQueue;
66 extern Queue g_configPollQueue;
67 extern Queue g_routePollQueue;
68 extern Queue g_discoveryPollQueue;
69 extern Queue g_nodePollerQueue;
70 extern Queue g_conditionPollerQueue;
71 extern Queue g_dataCollectionQueue;
72 extern Queue g_dciCacheLoaderQueue;
73
74 void UnregisterClientSession(int id);
75 void ResetDiscoveryPoller();
76 NXCPMessage *ForwardMessageToReportingServer(NXCPMessage *request, ClientSession *session);
77 void RemovePendingFileTransferRequests(ClientSession *session);
78
79 /**
80 * Node poller start data
81 */
82 typedef struct
83 {
84 ClientSession *pSession;
85 Node *pNode;
86 int iPollType;
87 UINT32 dwRqId;
88 } POLLER_START_DATA;
89
90 /**
91 * Additional processing thread start data
92 */
93 typedef struct
94 {
95 ClientSession *pSession;
96 NXCPMessage *pMsg;
97 } PROCTHREAD_START_DATA;
98
99 /**
100 * Object tool acl entry
101 */
102 typedef struct
103 {
104 UINT32 dwToolId;
105 UINT32 dwUserId;
106 } OBJECT_TOOL_ACL;
107
108 /**
109 *
110 */
111 typedef struct
112 {
113 uuid_t *guid;
114 bool removed;
115 } LIBRARY_IMAGE_UPDATE_INFO;
116
117 /**
118 * Callback to delete agent connections for loading files in distructor
119 */
120 static void DeleteCallback(NetObj* obj, void *data)
121 {
122 delete (AgentConnection *)obj;
123 }
124
125 /**
126 * Callback for sending image library update notifications
127 */
128 static void ImageLibraryUpdateCallback(ClientSession *pSession, void *pArg)
129 {
130 pSession->onLibraryImageChange((uuid_t *)pArg, false);
131 }
132
133 /**
134 * Callback for sending image library delete notifications
135 */
136 static void ImageLibraryDeleteCallback(ClientSession *pSession, void *pArg)
137 {
138 pSession->onLibraryImageChange((uuid_t *)pArg, true);
139 }
140
141 /**
142 * Additional message processing thread starters
143 */
144 #define CALL_IN_NEW_THREAD(func, msg) \
145 { \
146 PROCTHREAD_START_DATA *pData = (PROCTHREAD_START_DATA *)malloc(sizeof(PROCTHREAD_START_DATA)); \
147 pData->pSession = this; \
148 pData->pMsg = msg; \
149 msg = NULL; /* prevent deletion by main processing thread*/ \
150 m_dwRefCount++; \
151 ThreadCreate(ThreadStarter_##func, 0, pData); \
152 }
153
154 #define DEFINE_THREAD_STARTER(func) \
155 THREAD_RESULT THREAD_CALL ClientSession::ThreadStarter_##func(void *pArg) \
156 { \
157 ((PROCTHREAD_START_DATA *)pArg)->pSession->func(((PROCTHREAD_START_DATA *)pArg)->pMsg); \
158 ((PROCTHREAD_START_DATA *)pArg)->pSession->m_dwRefCount--; \
159 delete ((PROCTHREAD_START_DATA *)pArg)->pMsg; \
160 free(pArg); \
161 return THREAD_OK; \
162 }
163
164 DEFINE_THREAD_STARTER(getCollectedData)
165 DEFINE_THREAD_STARTER(getTableCollectedData)
166 DEFINE_THREAD_STARTER(clearDCIData)
167 DEFINE_THREAD_STARTER(queryL2Topology)
168 DEFINE_THREAD_STARTER(sendEventLog)
169 DEFINE_THREAD_STARTER(sendSyslog)
170 DEFINE_THREAD_STARTER(createObject)
171 DEFINE_THREAD_STARTER(getServerFile)
172 DEFINE_THREAD_STARTER(getAgentFile)
173 DEFINE_THREAD_STARTER(cancelFileMonitoring)
174 DEFINE_THREAD_STARTER(queryServerLog)
175 DEFINE_THREAD_STARTER(getServerLogQueryData)
176 DEFINE_THREAD_STARTER(executeAction)
177 DEFINE_THREAD_STARTER(findNodeConnection)
178 DEFINE_THREAD_STARTER(findMacAddress)
179 DEFINE_THREAD_STARTER(findIpAddress)
180 DEFINE_THREAD_STARTER(processConsoleCommand)
181 DEFINE_THREAD_STARTER(sendMib)
182 DEFINE_THREAD_STARTER(getNetworkPath)
183 DEFINE_THREAD_STARTER(queryParameter)
184 DEFINE_THREAD_STARTER(queryAgentTable)
185 DEFINE_THREAD_STARTER(getAlarmEvents)
186 DEFINE_THREAD_STARTER(openHelpdeskIssue)
187 DEFINE_THREAD_STARTER(forwardToReportingServer)
188 DEFINE_THREAD_STARTER(fileManagerControl)
189 DEFINE_THREAD_STARTER(uploadUserFileToAgent)
190 DEFINE_THREAD_STARTER(getSwitchForwardingDatabase)
191 DEFINE_THREAD_STARTER(getRoutingTable)
192 DEFINE_THREAD_STARTER(getLocationHistory)
193 DEFINE_THREAD_STARTER(executeScript)
194
195 /**
196 * Client communication read thread starter
197 */
198 THREAD_RESULT THREAD_CALL ClientSession::readThreadStarter(void *pArg)
199 {
200 ((ClientSession *)pArg)->readThread();
201
202 // When ClientSession::ReadThread exits, all other session
203 // threads are already stopped, so we can safely destroy
204 // session object
205 UnregisterClientSession(((ClientSession *)pArg)->getId());
206 delete (ClientSession *)pArg;
207 return THREAD_OK;
208 }
209
210 /**
211 * Client communication write thread starter
212 */
213 THREAD_RESULT THREAD_CALL ClientSession::writeThreadStarter(void *pArg)
214 {
215 ((ClientSession *)pArg)->writeThread();
216 return THREAD_OK;
217 }
218
219 /**
220 * Received message processing thread starter
221 */
222 THREAD_RESULT THREAD_CALL ClientSession::processingThreadStarter(void *pArg)
223 {
224 ((ClientSession *)pArg)->processingThread();
225 return THREAD_OK;
226 }
227
228 /**
229 * Information update processing thread starter
230 */
231 THREAD_RESULT THREAD_CALL ClientSession::updateThreadStarter(void *pArg)
232 {
233 ((ClientSession *)pArg)->updateThread();
234 return THREAD_OK;
235 }
236
237 /**
238 * Forced node poll thread starter
239 */
240 THREAD_RESULT THREAD_CALL ClientSession::pollerThreadStarter(void *pArg)
241 {
242 ((POLLER_START_DATA *)pArg)->pSession->pollerThread(
243 ((POLLER_START_DATA *)pArg)->pNode,
244 ((POLLER_START_DATA *)pArg)->iPollType,
245 ((POLLER_START_DATA *)pArg)->dwRqId);
246 ((POLLER_START_DATA *)pArg)->pSession->decRefCount();
247 free(pArg);
248 return THREAD_OK;
249 }
250
251 /**
252 * Client session class constructor
253 */
254 ClientSession::ClientSession(SOCKET hSocket, struct sockaddr *addr)
255 {
256 m_pSendQueue = new Queue;
257 m_pMessageQueue = new Queue;
258 m_pUpdateQueue = new Queue;
259 m_hSocket = hSocket;
260 m_id = -1;
261 m_state = SESSION_STATE_INIT;
262 m_pMsgBuffer = (NXCP_BUFFER *)malloc(sizeof(NXCP_BUFFER));
263 m_pCtx = NULL;
264 m_hWriteThread = INVALID_THREAD_HANDLE;
265 m_hProcessingThread = INVALID_THREAD_HANDLE;
266 m_hUpdateThread = INVALID_THREAD_HANDLE;
267 m_mutexSocketWrite = MutexCreate();
268 m_mutexSendEvents = MutexCreate();
269 m_mutexSendSyslog = MutexCreate();
270 m_mutexSendTrapLog = MutexCreate();
271 m_mutexSendObjects = MutexCreate();
272 m_mutexSendAlarms = MutexCreate();
273 m_mutexSendActions = MutexCreate();
274 m_mutexSendAuditLog = MutexCreate();
275 m_mutexSendSituations = MutexCreate();
276 m_mutexPollerInit = MutexCreate();
277 m_dwFlags = 0;
278 m_clientType = CLIENT_TYPE_DESKTOP;
279 m_clientAddr = (struct sockaddr *)nx_memdup(addr, (addr->sa_family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6));
280 if (addr->sa_family == AF_INET)
281 IpToStr(ntohl(((struct sockaddr_in *)m_clientAddr)->sin_addr.s_addr), m_workstation);
282 #ifdef WITH_IPV6
283 else
284 Ip6ToStr(((struct sockaddr_in6 *)m_clientAddr)->sin6_addr.s6_addr, m_workstation);
285 #endif
286 m_webServerAddress[0] = 0;
287 _tcscpy(m_szUserName, _T("<not logged in>"));
288 _tcscpy(m_szClientInfo, _T("n/a"));
289 m_dwUserId = INVALID_INDEX;
290 m_dwOpenDCIListSize = 0;
291 m_pOpenDCIList = NULL;
292 m_ppEPPRuleList = NULL;
293 m_hCurrFile = -1;
294 m_dwFileRqId = 0;
295 m_dwRefCount = 0;
296 m_dwEncryptionRqId = 0;
297 m_condEncryptionSetup = INVALID_CONDITION_HANDLE;
298 m_dwActiveChannels = 0;
299 m_console = NULL;
300 m_loginTime = time(NULL);
301 m_musicTypeList.add(_T("wav"));
302 _tcscpy(m_language, _T("en"));
303 }
304
305 /**
306 * Destructor
307 */
308 ClientSession::~ClientSession()
309 {
310 if (m_hSocket != -1)
311 closesocket(m_hSocket);
312 delete m_pSendQueue;
313 delete m_pMessageQueue;
314 delete m_pUpdateQueue;
315 safe_free(m_pMsgBuffer);
316 safe_free(m_clientAddr);
317 MutexDestroy(m_mutexSocketWrite);
318 MutexDestroy(m_mutexSendEvents);
319 MutexDestroy(m_mutexSendSyslog);
320 MutexDestroy(m_mutexSendTrapLog);
321 MutexDestroy(m_mutexSendObjects);
322 MutexDestroy(m_mutexSendAlarms);
323 MutexDestroy(m_mutexSendActions);
324 MutexDestroy(m_mutexSendAuditLog);
325 MutexDestroy(m_mutexSendSituations);
326 MutexDestroy(m_mutexPollerInit);
327 safe_free(m_pOpenDCIList);
328 if (m_ppEPPRuleList != NULL)
329 {
330 UINT32 i;
331
332 if (m_dwFlags & CSF_EPP_UPLOAD) // Aborted in the middle of EPP transfer
333 for(i = 0; i < m_dwRecordsUploaded; i++)
334 delete m_ppEPPRuleList[i];
335 free(m_ppEPPRuleList);
336 }
337 if (m_pCtx != NULL)
338 m_pCtx->decRefCount();
339 if (m_condEncryptionSetup != INVALID_CONDITION_HANDLE)
340 ConditionDestroy(m_condEncryptionSetup);
341
342 if (m_console != NULL)
343 {
344 delete m_console->pMsg;
345 free(m_console);
346 }
347 m_musicTypeList.clear();
348 if (m_agentConn.size() > 0)
349 {
350 m_agentConn.forEach(&DeleteCallback, NULL);
351 }
352 }
353
354 /**
355 * Start all threads
356 */
357 void ClientSession::run()
358 {
359 m_hWriteThread = ThreadCreateEx(writeThreadStarter, 0, this);
360 m_hProcessingThread = ThreadCreateEx(processingThreadStarter, 0, this);
361 m_hUpdateThread = ThreadCreateEx(updateThreadStarter, 0, this);
362 ThreadCreate(readThreadStarter, 0, this);
363 }
364
365 /**
366 * Print debug information
367 */
368 void ClientSession::debugPrintf(int level, const TCHAR *format, ...)
369 {
370 if (level <= (int)g_debugLevel)
371 {
372 va_list args;
373 TCHAR buffer[8192];
374
375 va_start(args, format);
376 _vsntprintf(buffer, 8192, format, args);
377 va_end(args);
378 DbgPrintf(level, _T("[CLSN-%d] %s"), m_id, buffer);
379 }
380 }
381
382 /**
383 * Read thread
384 */
385 void ClientSession::readThread()
386 {
387 TCHAR szBuffer[256];
388 UINT32 i;
389 NetObj *object;
390
391 SocketMessageReceiver receiver(m_hSocket, 4096, MAX_MSG_SIZE);
392 while(true)
393 {
394 MessageReceiverResult result;
395 NXCPMessage *msg = receiver.readMessage(900000, &result);
396
397 // Check for decryption error
398 if (result == MSGRECV_DECRYPTION_FAILURE)
399 {
400 debugPrintf(4, _T("readThread: Unable to decrypt received message"));
401 continue;
402 }
403
404 // Receive error
405 if (msg == NULL)
406 {
407 debugPrintf(5, _T("readThread: message receiving error (%s)"), AbstractMessageReceiver::resultToText(result));
408 break;
409 }
410
411 if (g_debugLevel >= 8)
412 {
413 String msgDump = NXCPMessage::dump(receiver.getRawMessageBuffer(), NXCP_VERSION);
414 debugPrintf(8, _T("Message dump:\n%s"), (const TCHAR *)msgDump);
415 }
416
417 // Special handling for raw messages
418 if (msg->isBinary())
419 {
420 debugPrintf(6, _T("Received raw message %s"), NXCPMessageCodeName(msg->getCode(), szBuffer));
421
422 if ((msg->getCode() == CMD_FILE_DATA) ||
423 (msg->getCode() == CMD_ABORT_FILE_TRANSFER))
424 {
425 if ((m_hCurrFile != -1) && (m_dwFileRqId == msg->getId()))
426 {
427 if (msg->getCode() == CMD_FILE_DATA)
428 {
429 if (write(m_hCurrFile, msg->getBinaryData(), (int)msg->getBinaryDataSize()) == (int)msg->getBinaryDataSize())
430 {
431 if (msg->isEndOfFile())
432 {
433 debugPrintf(6, _T("Got end of file marker"));
434 NXCPMessage response;
435
436 close(m_hCurrFile);
437 m_hCurrFile = -1;
438
439 response.setCode(CMD_REQUEST_COMPLETED);
440 response.setId(msg->getId());
441 response.setField(VID_RCC, RCC_SUCCESS);
442 sendMessage(&response);
443
444 onFileUpload(TRUE);
445 }
446 }
447 else
448 {
449 debugPrintf(6, _T("I/O error"));
450 // I/O error
451 NXCPMessage response;
452
453 close(m_hCurrFile);
454 m_hCurrFile = -1;
455
456 response.setCode(CMD_REQUEST_COMPLETED);
457 response.setId(msg->getId());
458 response.setField(VID_RCC, RCC_IO_ERROR);
459 sendMessage(&response);
460
461 onFileUpload(FALSE);
462 }
463 }
464 else
465 {
466 // Abort current file transfer because of client's problem
467 close(m_hCurrFile);
468 m_hCurrFile = -1;
469
470 onFileUpload(FALSE);
471 }
472 }
473 else
474 {
475 AgentConnection *conn = (AgentConnection *)m_agentConn.get(msg->getId());
476 if (conn != NULL)
477 {
478 if (msg->getCode() == CMD_FILE_DATA)
479 {
480 if (conn->sendMessage(msg)) //send raw message
481 {
482 if (msg->isEndOfFile())
483 {
484 debugPrintf(6, _T("Got end of file marker"));
485 //get response with specific ID if ok< then send ok, else send error
486 m_agentConn.remove(msg->getId());
487 delete conn;
488
489 NXCPMessage response;
490 response.setCode(CMD_REQUEST_COMPLETED);
491 response.setId(msg->getId());
492 response.setField(VID_RCC, RCC_SUCCESS);
493 sendMessage(&response);
494 }
495 }
496 else
497 {
498 debugPrintf(6, _T("Error while sending to agent"));
499 // I/O error
500 m_agentConn.remove(msg->getId());
501 delete conn;
502
503 NXCPMessage response;
504 response.setCode(CMD_REQUEST_COMPLETED);
505 response.setId(msg->getId());
506 response.setField(VID_RCC, RCC_IO_ERROR); //set result that came from agent
507 sendMessage(&response);
508 }
509 }
510 else
511 {
512 // Resend abort message
513 conn->sendMessage(msg);
514 m_agentConn.remove(msg->getId());
515 delete conn;
516 }
517 }
518 else
519 {
520 debugPrintf(4, _T("Out of state message (ID: %d)"), msg->getId());
521 }
522 }
523 }
524 delete msg;
525 }
526 else
527 {
528 if ((msg->getCode() == CMD_SESSION_KEY) && (msg->getId() == m_dwEncryptionRqId))
529 {
530 debugPrintf(6, _T("Received message %s"), NXCPMessageCodeName(msg->getCode(), szBuffer));
531 m_dwEncryptionResult = SetupEncryptionContext(msg, &m_pCtx, NULL, g_pServerKey, NXCP_VERSION);
532 receiver.setEncryptionContext(m_pCtx);
533 ConditionSet(m_condEncryptionSetup);
534 m_dwEncryptionRqId = 0;
535 delete msg;
536 }
537 else if (msg->getCode() == CMD_KEEPALIVE)
538 {
539 debugPrintf(6, _T("Received message %s"), NXCPMessageCodeName(msg->getCode(), szBuffer));
540 respondToKeepalive(msg->getId());
541 delete msg;
542 }
543 else
544 {
545 m_pMessageQueue->Put(msg);
546 }
547 }
548 }
549
550 // Finish update thread first
551 m_pUpdateQueue->Put(INVALID_POINTER_VALUE);
552 ThreadJoin(m_hUpdateThread);
553
554 // Notify other threads to exit
555 NXCP_MESSAGE *rawMsg;
556 while((rawMsg = (NXCP_MESSAGE *)m_pSendQueue->Get()) != NULL)
557 free(rawMsg);
558 m_pSendQueue->Put(INVALID_POINTER_VALUE);
559
560 NXCPMessage *msg;
561 while((msg = (NXCPMessage *)m_pMessageQueue->Get()) != NULL)
562 delete msg;
563 m_pMessageQueue->Put(INVALID_POINTER_VALUE);
564
565 // Wait for other threads to finish
566 ThreadJoin(m_hWriteThread);
567 ThreadJoin(m_hProcessingThread);
568
569 // Abort current file upload operation, if any
570 if (m_hCurrFile != -1)
571 {
572 close(m_hCurrFile);
573 m_hCurrFile = -1;
574 onFileUpload(FALSE);
575 }
576
577 // remove all pending file transfers from reporting server
578 RemovePendingFileTransferRequests(this);
579
580 // Remove all locks created by this session
581 RemoveAllSessionLocks(m_id);
582 for(i = 0; i < m_dwOpenDCIListSize; i++)
583 {
584 object = FindObjectById(m_pOpenDCIList[i]);
585 if (object != NULL)
586 if ((object->getObjectClass() == OBJECT_NODE) ||
587 (object->getObjectClass() == OBJECT_CLUSTER) ||
588 (object->getObjectClass() == OBJECT_TEMPLATE))
589 ((Template *)object)->unlockDCIList(m_id);
590 }
591
592 // Waiting while reference count becomes 0
593 if (m_dwRefCount > 0)
594 {
595 debugPrintf(3, _T("Waiting for pending requests..."));
596 do
597 {
598 ThreadSleep(1);
599 } while(m_dwRefCount > 0);
600 }
601
602 if (m_dwFlags & CSF_AUTHENTICATED)
603 {
604 CALL_ALL_MODULES(pfClientSessionClose, (this));
605 WriteAuditLog(AUDIT_SECURITY, TRUE, m_dwUserId, m_workstation, m_id, 0, _T("User logged out (client: %s)"), m_szClientInfo);
606 }
607 debugPrintf(3, _T("Session closed"));
608 }
609
610 /**
611 * Network write thread
612 */
613 void ClientSession::writeThread()
614 {
615 while(true)
616 {
617 NXCP_MESSAGE *rawMsg = (NXCP_MESSAGE *)m_pSendQueue->GetOrBlock();
618 if (rawMsg == INVALID_POINTER_VALUE) // Session termination indicator
619 break;
620
621 if (ntohs(rawMsg->code) != CMD_ADM_MESSAGE)
622 {
623 TCHAR buffer[256];
624 debugPrintf(6, _T("Sending message %s"), NXCPMessageCodeName(ntohs(rawMsg->code), buffer));
625 }
626
627 bool result;
628 if (m_pCtx != NULL)
629 {
630 NXCP_ENCRYPTED_MESSAGE *enMsg = m_pCtx->encryptMessage(rawMsg);
631 if (enMsg != NULL)
632 {
633 result = (SendEx(m_hSocket, (char *)enMsg, ntohl(enMsg->size), 0, m_mutexSocketWrite) == (int)ntohl(enMsg->size));
634 free(enMsg);
635 }
636 else
637 {
638 result = false;
639 }
640 }
641 else
642 {
643 result = (SendEx(m_hSocket, (const char *)rawMsg, ntohl(rawMsg->size), 0, m_mutexSocketWrite) == (int)ntohl(rawMsg->size));
644 }
645 free(rawMsg);
646
647 if (!result)
648 {
649 closesocket(m_hSocket);
650 m_hSocket = -1;
651 break;
652 }
653 }
654 }
655
656 /**
657 * Update processing thread
658 */
659 void ClientSession::updateThread()
660 {
661 UPDATE_INFO *pUpdate;
662 NXCPMessage msg;
663
664 while(1)
665 {
666 pUpdate = (UPDATE_INFO *)m_pUpdateQueue->GetOrBlock();
667 if (pUpdate == INVALID_POINTER_VALUE) // Session termination indicator
668 break;
669
670 switch(pUpdate->dwCategory)
671 {
672 case INFO_CAT_EVENT:
673 MutexLock(m_mutexSendEvents);
674 sendMessage((NXCPMessage *)pUpdate->pData);
675 MutexUnlock(m_mutexSendEvents);
676 delete (NXCPMessage *)pUpdate->pData;
677 break;
678 case INFO_CAT_SYSLOG_MSG:
679 MutexLock(m_mutexSendSyslog);
680 msg.setCode(CMD_SYSLOG_RECORDS);
681 CreateMessageFromSyslogMsg(&msg, (NX_SYSLOG_RECORD *)pUpdate->pData);
682 sendMessage(&msg);
683 MutexUnlock(m_mutexSendSyslog);
684 free(pUpdate->pData);
685 break;
686 case INFO_CAT_SNMP_TRAP:
687 MutexLock(m_mutexSendTrapLog);
688 sendMessage((NXCPMessage *)pUpdate->pData);
689 MutexUnlock(m_mutexSendTrapLog);
690 delete (NXCPMessage *)pUpdate->pData;
691 break;
692 case INFO_CAT_AUDIT_RECORD:
693 MutexLock(m_mutexSendAuditLog);
694 sendMessage((NXCPMessage *)pUpdate->pData);
695 MutexUnlock(m_mutexSendAuditLog);
696 delete (NXCPMessage *)pUpdate->pData;
697 break;
698 case INFO_CAT_OBJECT_CHANGE:
699 MutexLock(m_mutexSendObjects);
700 msg.setCode(CMD_OBJECT_UPDATE);
701 if (!((NetObj *)pUpdate->pData)->isDeleted())
702 {
703 ((NetObj *)pUpdate->pData)->fillMessage(&msg);
704 if (m_dwFlags & CSF_SYNC_OBJECT_COMMENTS)
705 ((NetObj *)pUpdate->pData)->commentsToMessage(&msg);
706 }
707 else
708 {
709 msg.setField(VID_OBJECT_ID, ((NetObj *)pUpdate->pData)->getId());
710 msg.setField(VID_IS_DELETED, (WORD)1);
711 }
712 sendMessage(&msg);
713 MutexUnlock(m_mutexSendObjects);
714 msg.deleteAllFields();
715 ((NetObj *)pUpdate->pData)->decRefCount();
716 break;
717 case INFO_CAT_ALARM:
718 MutexLock(m_mutexSendAlarms);
719 msg.setCode(CMD_ALARM_UPDATE);
720 msg.setField(VID_NOTIFICATION_CODE, pUpdate->dwCode);
721 FillAlarmInfoMessage(&msg, (NXC_ALARM *)pUpdate->pData);
722 sendMessage(&msg);
723 MutexUnlock(m_mutexSendAlarms);
724 msg.deleteAllFields();
725 free(pUpdate->pData);
726 break;
727 case INFO_CAT_ACTION:
728 MutexLock(m_mutexSendActions);
729 msg.setCode(CMD_ACTION_DB_UPDATE);
730 msg.setField(VID_NOTIFICATION_CODE, pUpdate->dwCode);
731 msg.setField(VID_ACTION_ID, ((NXC_ACTION *)pUpdate->pData)->dwId);
732 if (pUpdate->dwCode != NX_NOTIFY_ACTION_DELETED)
733 FillActionInfoMessage(&msg, (NXC_ACTION *)pUpdate->pData);
734 sendMessage(&msg);
735 MutexUnlock(m_mutexSendActions);
736 msg.deleteAllFields();
737 free(pUpdate->pData);
738 break;
739 case INFO_CAT_SITUATION:
740 MutexLock(m_mutexSendSituations);
741 sendMessage((NXCPMessage *)pUpdate->pData);
742 MutexUnlock(m_mutexSendSituations);
743 delete (NXCPMessage *)pUpdate->pData;
744 break;
745 case INFO_CAT_LIBRARY_IMAGE:
746 {
747 LIBRARY_IMAGE_UPDATE_INFO *info = (LIBRARY_IMAGE_UPDATE_INFO *)pUpdate->pData;
748 msg.setCode(CMD_IMAGE_LIBRARY_UPDATE);
749 msg.setField(VID_GUID, (BYTE *)info->guid, UUID_LENGTH);
750 if (info->removed)
751 {
752 msg.setField(VID_FLAGS, (UINT32)1);
753 }
754 else
755 {
756 msg.setField(VID_FLAGS, (UINT32)0);
757 }
758 sendMessage(&msg);
759 msg.deleteAllFields();
760 free(info->guid);
761 free(info);
762 }
763 break;
764 default:
765 break;
766 }
767
768 free(pUpdate);
769 }
770 }
771
772 /**
773 * Message processing thread
774 */
775 void ClientSession::processingThread()
776 {
777 NXCPMessage *pMsg;
778 TCHAR szBuffer[128];
779 UINT32 i;
780 int status;
781
782 while(1)
783 {
784 pMsg = (NXCPMessage *)m_pMessageQueue->GetOrBlock();
785 if (pMsg == INVALID_POINTER_VALUE) // Session termination indicator
786 break;
787
788 m_wCurrentCmd = pMsg->getCode();
789 debugPrintf(6, _T("Received message %s"), NXCPMessageCodeName(m_wCurrentCmd, szBuffer));
790 if (!(m_dwFlags & CSF_AUTHENTICATED) &&
791 (m_wCurrentCmd != CMD_LOGIN) &&
792 (m_wCurrentCmd != CMD_GET_SERVER_INFO) &&
793 (m_wCurrentCmd != CMD_REQUEST_ENCRYPTION) &&
794 (m_wCurrentCmd != CMD_GET_MY_CONFIG) &&
795 (m_wCurrentCmd != CMD_REGISTER_AGENT))
796 {
797 delete pMsg;
798 continue;
799 }
800
801 m_state = SESSION_STATE_PROCESSING;
802 switch(m_wCurrentCmd)
803 {
804 case CMD_LOGIN:
805 login(pMsg);
806 break;
807 case CMD_GET_SERVER_INFO:
808 sendServerInfo(pMsg->getId());
809 break;
810 case CMD_GET_MY_CONFIG:
811 sendConfigForAgent(pMsg);
812 break;
813 case CMD_GET_OBJECTS:
814 sendAllObjects(pMsg);
815 break;
816 case CMD_GET_SELECTED_OBJECTS:
817 sendSelectedObjects(pMsg);
818 break;
819 case CMD_GET_EVENTS:
820 CALL_IN_NEW_THREAD(sendEventLog, pMsg);
821 break;
822 case CMD_GET_CONFIG_VARLIST:
823 sendAllConfigVars(pMsg->getId());
824 break;
825 case CMD_SET_CONFIG_VARIABLE:
826 setConfigVariable(pMsg);
827 break;
828 case CMD_DELETE_CONFIG_VARIABLE:
829 deleteConfigVariable(pMsg);
830 break;
831 case CMD_CONFIG_GET_CLOB:
832 getConfigCLOB(pMsg);
833 break;
834 case CMD_CONFIG_SET_CLOB:
835 setConfigCLOB(pMsg);
836 break;
837 case CMD_LOAD_EVENT_DB:
838 sendEventDB(pMsg->getId());
839 break;
840 case CMD_SET_EVENT_INFO:
841 modifyEventTemplate(pMsg);
842 break;
843 case CMD_DELETE_EVENT_TEMPLATE:
844 deleteEventTemplate(pMsg);
845 break;
846 case CMD_GENERATE_EVENT_CODE:
847 generateEventCode(pMsg->getId());
848 break;
849 case CMD_MODIFY_OBJECT:
850 modifyObject(pMsg);
851 break;
852 case CMD_SET_OBJECT_MGMT_STATUS:
853 changeObjectMgmtStatus(pMsg);
854 break;
855 case CMD_LOAD_USER_DB:
856 sendUserDB(pMsg->getId());
857 break;
858 case CMD_CREATE_USER:
859 createUser(pMsg);
860 break;
861 case CMD_UPDATE_USER:
862 updateUser(pMsg);
863 break;
864 case CMD_DELETE_USER:
865 deleteUser(pMsg);
866 break;
867 case CMD_LOCK_USER_DB:
868 lockUserDB(pMsg->getId(), TRUE);
869 break;
870 case CMD_UNLOCK_USER_DB:
871 lockUserDB(pMsg->getId(), FALSE);
872 break;
873 case CMD_SET_PASSWORD:
874 setPassword(pMsg);
875 break;
876 case CMD_GET_NODE_DCI_LIST:
877 openNodeDCIList(pMsg);
878 break;
879 case CMD_UNLOCK_NODE_DCI_LIST:
880 closeNodeDCIList(pMsg);
881 break;
882 case CMD_CREATE_NEW_DCI:
883 case CMD_MODIFY_NODE_DCI:
884 case CMD_DELETE_NODE_DCI:
885 modifyNodeDCI(pMsg);
886 break;
887 case CMD_SET_DCI_STATUS:
888 changeDCIStatus(pMsg);
889 break;
890 case CMD_COPY_DCI:
891 copyDCI(pMsg);
892 break;
893 case CMD_APPLY_TEMPLATE:
894 applyTemplate(pMsg);
895 break;
896 case CMD_GET_DCI_DATA:
897 CALL_IN_NEW_THREAD(getCollectedData, pMsg);
898 break;
899 case CMD_GET_TABLE_DCI_DATA:
900 CALL_IN_NEW_THREAD(getTableCollectedData, pMsg);
901 break;
902 case CMD_CLEAR_DCI_DATA:
903 CALL_IN_NEW_THREAD(clearDCIData, pMsg);
904 break;
905 case CMD_OPEN_EPP:
906 openEPP(pMsg);
907 break;
908 case CMD_CLOSE_EPP:
909 closeEPP(pMsg->getId());
910 break;
911 case CMD_SAVE_EPP:
912 saveEPP(pMsg);
913 break;
914 case CMD_EPP_RECORD:
915 processEPPRecord(pMsg);
916 break;
917 case CMD_GET_MIB_TIMESTAMP:
918 sendMIBTimestamp(pMsg->getId());
919 break;
920 case CMD_GET_MIB:
921 CALL_IN_NEW_THREAD(sendMib, pMsg);
922 break;
923 case CMD_CREATE_OBJECT:
924 CALL_IN_NEW_THREAD(createObject, pMsg);
925 break;
926 case CMD_BIND_OBJECT:
927 changeObjectBinding(pMsg, TRUE);
928 break;
929 case CMD_UNBIND_OBJECT:
930 changeObjectBinding(pMsg, FALSE);
931 break;
932 case CMD_ADD_CLUSTER_NODE:
933 addClusterNode(pMsg);
934 break;
935 case CMD_GET_ALL_ALARMS:
936 sendAllAlarms(pMsg->getId());
937 break;
938 case CMD_GET_ALARM_COMMENTS:
939 getAlarmComments(pMsg);
940 break;
941 case CMD_SET_ALARM_STATUS_FLOW:
942 updateAlarmStatusFlow(pMsg);
943 break;
944 case CMD_UPDATE_ALARM_COMMENT:
945 updateAlarmComment(pMsg);
946 break;
947 case CMD_DELETE_ALARM_COMMENT:
948 deleteAlarmComment(pMsg);
949 break;
950 case CMD_GET_ALARM:
951 getAlarm(pMsg);
952 break;
953 case CMD_GET_ALARM_EVENTS:
954 CALL_IN_NEW_THREAD(getAlarmEvents, pMsg);
955 break;
956 case CMD_ACK_ALARM:
957 acknowledgeAlarm(pMsg);
958 break;
959 case CMD_RESOLVE_ALARM:
960 resolveAlarm(pMsg, false);
961 break;
962 case CMD_TERMINATE_ALARM:
963 resolveAlarm(pMsg, true);
964 break;
965 case CMD_DELETE_ALARM:
966 deleteAlarm(pMsg);
967 break;
968 case CMD_OPEN_HELPDESK_ISSUE:
969 CALL_IN_NEW_THREAD(openHelpdeskIssue, pMsg);
970 break;
971 case CMD_GET_HELPDESK_URL:
972 getHelpdeskUrl(pMsg);
973 break;
974 case CMD_UNLINK_HELPDESK_ISSUE:
975 unlinkHelpdeskIssue(pMsg);
976 break;
977 case CMD_CREATE_ACTION:
978 createAction(pMsg);
979 break;
980 case CMD_MODIFY_ACTION:
981 updateAction(pMsg);
982 break;
983 case CMD_DELETE_ACTION:
984 deleteAction(pMsg);
985 break;
986 case CMD_LOAD_ACTIONS:
987 sendAllActions(pMsg->getId());
988 break;
989 case CMD_GET_CONTAINER_CAT_LIST:
990 SendContainerCategories(pMsg->getId());
991 break;
992 case CMD_DELETE_OBJECT:
993 deleteObject(pMsg);
994 break;
995 case CMD_POLL_NODE:
996 forcedNodePoll(pMsg);
997 break;
998 case CMD_TRAP:
999 onTrap(pMsg);
1000 break;
1001 case CMD_WAKEUP_NODE:
1002 onWakeUpNode(pMsg);
1003 break;
1004 case CMD_CREATE_TRAP:
1005 editTrap(TRAP_CREATE, pMsg);
1006 break;
1007 case CMD_MODIFY_TRAP:
1008 editTrap(TRAP_UPDATE, pMsg);
1009 break;
1010 case CMD_DELETE_TRAP:
1011 editTrap(TRAP_DELETE, pMsg);
1012 break;
1013 case CMD_LOAD_TRAP_CFG:
1014 sendAllTraps(pMsg->getId());
1015 break;
1016 case CMD_GET_TRAP_CFG_RO:
1017 sendAllTraps2(pMsg->getId());
1018 break;
1019 case CMD_QUERY_PARAMETER:
1020 CALL_IN_NEW_THREAD(queryParameter, pMsg);
1021 break;
1022 case CMD_QUERY_TABLE:
1023 CALL_IN_NEW_THREAD(queryAgentTable, pMsg);
1024 break;
1025 case CMD_LOCK_PACKAGE_DB:
1026 LockPackageDB(pMsg->getId(), TRUE);
1027 break;
1028 case CMD_UNLOCK_PACKAGE_DB:
1029 LockPackageDB(pMsg->getId(), FALSE);
1030 break;
1031 case CMD_GET_PACKAGE_LIST:
1032 SendAllPackages(pMsg->getId());
1033 break;
1034 case CMD_INSTALL_PACKAGE:
1035 InstallPackage(pMsg);
1036 break;
1037 case CMD_REMOVE_PACKAGE:
1038 RemovePackage(pMsg);
1039 break;
1040 case CMD_GET_PARAMETER_LIST:
1041 getParametersList(pMsg);
1042 break;
1043 case CMD_DEPLOY_PACKAGE:
1044 DeployPackage(pMsg);
1045 break;
1046 case CMD_GET_LAST_VALUES:
1047 getLastValues(pMsg);
1048 break;
1049 case CMD_GET_DCI_VALUES:
1050 getLastValuesByDciId(pMsg);
1051 break;
1052 case CMD_GET_TABLE_LAST_VALUES:
1053 getTableLastValues(pMsg);
1054 break;
1055 case CMD_GET_THRESHOLD_SUMMARY:
1056 getThresholdSummary(pMsg);
1057 break;
1058 case CMD_GET_USER_VARIABLE:
1059 getUserVariable(pMsg);
1060 break;
1061 case CMD_SET_USER_VARIABLE:
1062 setUserVariable(pMsg);
1063 break;
1064 case CMD_DELETE_USER_VARIABLE:
1065 deleteUserVariable(pMsg);
1066 break;
1067 case CMD_ENUM_USER_VARIABLES:
1068 enumUserVariables(pMsg);
1069 break;
1070 case CMD_COPY_USER_VARIABLE:
1071 copyUserVariable(pMsg);
1072 break;
1073 case CMD_CHANGE_ZONE:
1074 changeObjectZone(pMsg);
1075 break;
1076 case CMD_REQUEST_ENCRYPTION:
1077 setupEncryption(pMsg);
1078 break;
1079 case CMD_GET_AGENT_CONFIG:
1080 getAgentConfig(pMsg);
1081 break;
1082 case CMD_UPDATE_AGENT_CONFIG:
1083 updateAgentConfig(pMsg);
1084 break;
1085 case CMD_EXECUTE_ACTION:
1086 CALL_IN_NEW_THREAD(executeAction, pMsg);
1087 break;
1088 case CMD_GET_OBJECT_TOOLS:
1089 sendObjectTools(pMsg->getId());
1090 break;
1091 case CMD_EXEC_TABLE_TOOL:
1092 execTableTool(pMsg);
1093 break;
1094 case CMD_GET_OBJECT_TOOL_DETAILS:
1095 sendObjectToolDetails(pMsg);
1096 break;
1097 case CMD_UPDATE_OBJECT_TOOL:
1098 updateObjectTool(pMsg);
1099 break;
1100 case CMD_DELETE_OBJECT_TOOL:
1101 deleteObjectTool(pMsg);
1102 break;
1103 case CMD_CHANGE_OBJECT_TOOL_STATUS:
1104 changeObjectToolStatus(pMsg);
1105 break;
1106 case CMD_GENERATE_OBJECT_TOOL_ID:
1107 generateObjectToolId(pMsg->getId());
1108 break;
1109 case CMD_CHANGE_SUBSCRIPTION:
1110 changeSubscription(pMsg);
1111 break;
1112 case CMD_GET_SYSLOG:
1113 CALL_IN_NEW_THREAD(sendSyslog, pMsg);
1114 break;
1115 case CMD_GET_SERVER_STATS:
1116 sendServerStats(pMsg->getId());
1117 break;
1118 case CMD_GET_SCRIPT_LIST:
1119 sendScriptList(pMsg->getId());
1120 break;
1121 case CMD_GET_SCRIPT:
1122 sendScript(pMsg);
1123 break;
1124 case CMD_UPDATE_SCRIPT:
1125 updateScript(pMsg);
1126 break;
1127 case CMD_RENAME_SCRIPT:
1128 renameScript(pMsg);
1129 break;
1130 case CMD_DELETE_SCRIPT:
1131 deleteScript(pMsg);
1132 break;
1133 case CMD_GET_SESSION_LIST:
1134 SendSessionList(pMsg->getId());
1135 break;
1136 case CMD_KILL_SESSION:
1137 KillSession(pMsg);
1138 break;
1139 case CMD_GET_TRAP_LOG:
1140 SendTrapLog(pMsg);
1141 break;
1142 case CMD_START_SNMP_WALK:
1143 StartSnmpWalk(pMsg);
1144 break;
1145 case CMD_RESOLVE_DCI_NAMES:
1146 resolveDCINames(pMsg);
1147 break;
1148 case CMD_GET_DCI_INFO:
1149 SendDCIInfo(pMsg);
1150 break;
1151 case CMD_GET_DCI_THRESHOLDS:
1152 sendDCIThresholds(pMsg);
1153 break;
1154 case CMD_GET_DCI_EVENTS_LIST:
1155 sendDCIEventList(pMsg);
1156 break;
1157 case CMD_GET_PERFTAB_DCI_LIST:
1158 sendPerfTabDCIList(pMsg);
1159 break;
1160 case CMD_PUSH_DCI_DATA:
1161 pushDCIData(pMsg);
1162 break;
1163 case CMD_GET_AGENT_CFG_LIST:
1164 sendAgentCfgList(pMsg->getId());
1165 break;
1166 case CMD_OPEN_AGENT_CONFIG:
1167 OpenAgentConfig(pMsg);
1168 break;
1169 case CMD_SAVE_AGENT_CONFIG:
1170 SaveAgentConfig(pMsg);
1171 break;
1172 case CMD_DELETE_AGENT_CONFIG:
1173 DeleteAgentConfig(pMsg);
1174 break;
1175 case CMD_SWAP_AGENT_CONFIGS:
1176 SwapAgentConfigs(pMsg);
1177 break;
1178 case CMD_GET_OBJECT_COMMENTS:
1179 SendObjectComments(pMsg);
1180 break;
1181 case CMD_UPDATE_OBJECT_COMMENTS:
1182 updateObjectComments(pMsg);
1183 break;
1184 case CMD_GET_ADDR_LIST:
1185 getAddrList(pMsg);
1186 break;
1187 case CMD_SET_ADDR_LIST:
1188 setAddrList(pMsg);
1189 break;
1190 case CMD_RESET_COMPONENT:
1191 resetComponent(pMsg);
1192 break;
1193 case CMD_EXPORT_CONFIGURATION:
1194 exportConfiguration(pMsg);
1195 break;
1196 case CMD_IMPORT_CONFIGURATION:
1197 importConfiguration(pMsg);
1198 break;
1199 case CMD_GET_GRAPH_LIST:
1200 sendGraphList(pMsg->getId());
1201 break;
1202 case CMD_SAVE_GRAPH:
1203 saveGraph(pMsg);
1204 break;
1205 case CMD_DELETE_GRAPH:
1206 deleteGraph(pMsg);
1207 break;
1208 case CMD_ADD_CA_CERTIFICATE:
1209 AddCACertificate(pMsg);
1210 break;
1211 case CMD_DELETE_CERTIFICATE:
1212 DeleteCertificate(pMsg);
1213 break;
1214 case CMD_UPDATE_CERT_COMMENTS:
1215 UpdateCertificateComments(pMsg);
1216 break;
1217 case CMD_GET_CERT_LIST:
1218 getCertificateList(pMsg->getId());
1219 break;
1220 case CMD_QUERY_L2_TOPOLOGY:
1221 CALL_IN_NEW_THREAD(queryL2Topology, pMsg);
1222 break;
1223 case CMD_SEND_SMS:
1224 sendSMS(pMsg);
1225 break;
1226 case CMD_GET_COMMUNITY_LIST:
1227 SendCommunityList(pMsg->getId());
1228 break;
1229 case CMD_UPDATE_COMMUNITY_LIST:
1230 UpdateCommunityList(pMsg);
1231 break;
1232 case CMD_GET_USM_CREDENTIALS:
1233 sendUsmCredentials(pMsg->getId());
1234 break;
1235 case CMD_UPDATE_USM_CREDENTIALS:
1236 updateUsmCredentials(pMsg);
1237 break;
1238 case CMD_GET_SITUATION_LIST:
1239 getSituationList(pMsg->getId());
1240 break;
1241 case CMD_CREATE_SITUATION:
1242 createSituation(pMsg);
1243 break;
1244 case CMD_UPDATE_SITUATION:
1245 updateSituation(pMsg);
1246 break;
1247 case CMD_DELETE_SITUATION:
1248 deleteSituation(pMsg);
1249 break;
1250 case CMD_DEL_SITUATION_INSTANCE:
1251 deleteSituationInstance(pMsg);
1252 break;
1253 case CMD_REGISTER_AGENT:
1254 registerAgent(pMsg);
1255 break;
1256 case CMD_GET_SERVER_FILE:
1257 CALL_IN_NEW_THREAD(getServerFile, pMsg);
1258 break;
1259 case CMD_GET_AGENT_FILE:
1260 CALL_IN_NEW_THREAD(getAgentFile, pMsg);
1261 break;
1262 case CMD_CANCEL_FILE_MONITORING:
1263 CALL_IN_NEW_THREAD(cancelFileMonitoring, pMsg);
1264 break;
1265 case CMD_TEST_DCI_TRANSFORMATION:
1266 testDCITransformation(pMsg);
1267 break;
1268 case CMD_EXECUTE_SCRIPT:
1269 CALL_IN_NEW_THREAD(executeScript, pMsg);
1270 break;
1271 case CMD_GET_JOB_LIST:
1272 sendJobList(pMsg->getId());
1273 break;
1274 case CMD_CANCEL_JOB:
1275 cancelJob(pMsg);
1276 break;
1277 case CMD_HOLD_JOB:
1278 holdJob(pMsg);
1279 break;
1280 case CMD_UNHOLD_JOB:
1281 unholdJob(pMsg);
1282 break;
1283 case CMD_DEPLOY_AGENT_POLICY:
1284 deployAgentPolicy(pMsg, false);
1285 break;
1286 case CMD_UNINSTALL_AGENT_POLICY:
1287 deployAgentPolicy(pMsg, true);
1288 break;
1289 case CMD_GET_CURRENT_USER_ATTR:
1290 getUserCustomAttribute(pMsg);
1291 break;
1292 case CMD_SET_CURRENT_USER_ATTR:
1293 setUserCustomAttribute(pMsg);
1294 break;
1295 case CMD_OPEN_SERVER_LOG:
1296 openServerLog(pMsg);
1297 break;
1298 case CMD_CLOSE_SERVER_LOG:
1299 closeServerLog(pMsg);
1300 break;
1301 case CMD_QUERY_LOG:
1302 CALL_IN_NEW_THREAD(queryServerLog, pMsg);
1303 break;
1304 case CMD_GET_LOG_DATA:
1305 CALL_IN_NEW_THREAD(getServerLogQueryData, pMsg);
1306 break;
1307 case CMD_FIND_NODE_CONNECTION:
1308 CALL_IN_NEW_THREAD(findNodeConnection, pMsg);
1309 break;
1310 case CMD_FIND_MAC_LOCATION:
1311 CALL_IN_NEW_THREAD(findMacAddress, pMsg);
1312 break;
1313 case CMD_FIND_IP_LOCATION:
1314 CALL_IN_NEW_THREAD(findIpAddress, pMsg);
1315 break;
1316 case CMD_GET_IMAGE:
1317 sendLibraryImage(pMsg);
1318 break;
1319 case CMD_CREATE_IMAGE:
1320 updateLibraryImage(pMsg);
1321 break;
1322 case CMD_DELETE_IMAGE:
1323 deleteLibraryImage(pMsg);
1324 break;
1325 case CMD_MODIFY_IMAGE:
1326 updateLibraryImage(pMsg);
1327 break;
1328 case CMD_LIST_IMAGES:
1329 listLibraryImages(pMsg);
1330 break;
1331 case CMD_EXECUTE_SERVER_COMMAND:
1332 executeServerCommand(pMsg);
1333 break;
1334 case CMD_LIST_SERVER_FILES:
1335 listServerFileStore(pMsg);
1336 break;
1337 case CMD_UPLOAD_FILE_TO_AGENT:
1338 uploadFileToAgent(pMsg);
1339 break;
1340 case CMD_UPLOAD_FILE:
1341 receiveFile(pMsg);
1342 break;
1343 case CMD_DELETE_FILE:
1344 deleteFile(pMsg);
1345 break;
1346 case CMD_OPEN_CONSOLE:
1347 openConsole(pMsg->getId());
1348 break;
1349 case CMD_CLOSE_CONSOLE:
1350 closeConsole(pMsg->getId());
1351 break;
1352 case CMD_ADM_REQUEST:
1353 CALL_IN_NEW_THREAD(processConsoleCommand, pMsg);
1354 break;
1355 case CMD_GET_VLANS:
1356 getVlans(pMsg);
1357 break;
1358 case CMD_GET_NETWORK_PATH:
1359 CALL_IN_NEW_THREAD(getNetworkPath, pMsg);
1360 break;
1361 case CMD_GET_NODE_COMPONENTS:
1362 getNodeComponents(pMsg);
1363 break;
1364 case CMD_GET_NODE_SOFTWARE:
1365 getNodeSoftware(pMsg);
1366 break;
1367 case CMD_GET_WINPERF_OBJECTS:
1368 getWinPerfObjects(pMsg);
1369 break;
1370 case CMD_LIST_MAPPING_TABLES:
1371 listMappingTables(pMsg);
1372 break;
1373 case CMD_GET_MAPPING_TABLE:
1374 getMappingTable(pMsg);
1375 break;
1376 case CMD_UPDATE_MAPPING_TABLE:
1377 updateMappingTable(pMsg);
1378 break;
1379 case CMD_DELETE_MAPPING_TABLE:
1380 deleteMappingTable(pMsg);
1381 break;
1382 case CMD_GET_WIRELESS_STATIONS:
1383 getWirelessStations(pMsg);
1384 break;
1385 case CMD_GET_SUMMARY_TABLES:
1386 getSummaryTables(pMsg->getId());
1387 break;
1388 case CMD_GET_SUMMARY_TABLE_DETAILS:
1389 getSummaryTableDetails(pMsg);
1390 break;
1391 case CMD_MODIFY_SUMMARY_TABLE:
1392 modifySummaryTable(pMsg);
1393 break;
1394 case CMD_DELETE_SUMMARY_TABLE:
1395 deleteSummaryTable(pMsg);
1396 break;
1397 case CMD_QUERY_SUMMARY_TABLE:
1398 querySummaryTable(pMsg);
1399 break;
1400 case CMD_QUERY_ADHOC_SUMMARY_TABLE:
1401 queryAdHocSummaryTable(pMsg);
1402 break;
1403 case CMD_GET_SUBNET_ADDRESS_MAP:
1404 getSubnetAddressMap(pMsg);
1405 break;
1406 case CMD_GET_EFFECTIVE_RIGHTS:
1407 getEffectiveRights(pMsg);
1408 break;
1409 case CMD_GET_FOLDER_CONTENT:
1410 case CMD_FILEMGR_DELETE_FILE:
1411 case CMD_FILEMGR_RENAME_FILE:
1412 case CMD_FILEMGR_MOVE_FILE:
1413 case CMD_FILEMGR_CREATE_FOLDER:
1414 CALL_IN_NEW_THREAD(fileManagerControl, pMsg);
1415 break;
1416 case CMD_FILEMGR_UPLOAD:
1417 CALL_IN_NEW_THREAD(uploadUserFileToAgent, pMsg);
1418 break;
1419 case CMD_GET_SWITCH_FDB:
1420 CALL_IN_NEW_THREAD(getSwitchForwardingDatabase, pMsg);
1421 break;
1422 case CMD_GET_ROUTING_TABLE:
1423 CALL_IN_NEW_THREAD(getRoutingTable, pMsg);
1424 break;
1425 case CMD_GET_LOC_HISTORY:
1426 CALL_IN_NEW_THREAD(getLocationHistory, pMsg);
1427 break;
1428 case CMD_TAKE_SCREENSHOT:
1429 getScreenshot(pMsg);
1430 break;
1431 default:
1432 if ((m_wCurrentCmd >> 8) == 0x11)
1433 {
1434 // Reporting Server range (0x1100 - 0x11FF)
1435 CALL_IN_NEW_THREAD(forwardToReportingServer, pMsg);
1436 break;
1437 }
1438
1439 // Pass message to loaded modules
1440 for(i = 0; i < g_dwNumModules; i++)
1441 {
1442 if (g_pModuleList[i].pfClientCommandHandler != NULL)
1443 {
1444 status = g_pModuleList[i].pfClientCommandHandler(m_wCurrentCmd, pMsg, this);
1445 if (status != NXMOD_COMMAND_IGNORED)
1446 {
1447 if (status == NXMOD_COMMAND_ACCEPTED_ASYNC)
1448 {
1449 pMsg = NULL; // Prevent deletion
1450 m_dwRefCount++;
1451 }
1452 break; // Message was processed by the module
1453 }
1454 }
1455 }
1456 if (i == g_dwNumModules)
1457 {
1458 NXCPMessage response;
1459
1460 response.setId(pMsg->getId());
1461 response.setCode(CMD_REQUEST_COMPLETED);
1462 response.setField(VID_RCC, RCC_NOT_IMPLEMENTED);
1463 sendMessage(&response);
1464 }
1465 break;
1466 }
1467 delete pMsg;
1468 m_state = (m_dwFlags & CSF_AUTHENTICATED) ? SESSION_STATE_IDLE : SESSION_STATE_INIT;
1469 }
1470 }
1471
1472 /**
1473 * Respond to client's keepalive message
1474 */
1475 void ClientSession::respondToKeepalive(UINT32 dwRqId)
1476 {
1477 NXCPMessage msg;
1478
1479 msg.setCode(CMD_REQUEST_COMPLETED);
1480 msg.setId(dwRqId);
1481 msg.setField(VID_RCC, RCC_SUCCESS);
1482 sendMessage(&msg);
1483 }
1484
1485 /**
1486 * Process received file
1487 */
1488 void ClientSession::onFileUpload(BOOL bSuccess)
1489 {
1490 // Do processing specific to command initiated file upload
1491 switch(m_dwUploadCommand)
1492 {
1493 case CMD_INSTALL_PACKAGE:
1494 if (!bSuccess)
1495 {
1496 TCHAR szQuery[256];
1497
1498 _sntprintf(szQuery, 256, _T("DELETE FROM agent_pkg WHERE pkg_id=%d"), m_dwUploadData);
1499 DBQuery(g_hCoreDB, szQuery);
1500 }
1501 break;
1502 case CMD_MODIFY_IMAGE:
1503 EnumerateClientSessions(ImageLibraryUpdateCallback, (void *)&m_uploadImageGuid);
1504 break;
1505 default:
1506 break;
1507 }
1508
1509 // Remove received file in case of failure
1510 if (!bSuccess)
1511 _tunlink(m_szCurrFileName);
1512 }
1513
1514 /**
1515 * Send message to client
1516 */
1517 void ClientSession::sendMessage(NXCPMessage *msg)
1518 {
1519 if (msg->getCode() != CMD_ADM_MESSAGE)
1520 {
1521 TCHAR buffer[128];
1522 debugPrintf(6, _T("Sending message %s"), NXCPMessageCodeName(msg->getCode(), buffer));
1523 }
1524
1525 NXCP_MESSAGE *rawMsg = msg->createMessage();
1526 if ((g_debugLevel >= 8) && (msg->getCode() != CMD_ADM_MESSAGE))
1527 {
1528 String msgDump = NXCPMessage::dump(rawMsg, NXCP_VERSION);
1529 debugPrintf(8, _T("Message dump:\n%s"), (const TCHAR *)msgDump);
1530 }
1531
1532 bool result;
1533 if (m_pCtx != NULL)
1534 {
1535 NXCP_ENCRYPTED_MESSAGE *enMsg = m_pCtx->encryptMessage(rawMsg);
1536 if (enMsg != NULL)
1537 {
1538 result = (SendEx(m_hSocket, (char *)enMsg, ntohl(enMsg->size), 0, m_mutexSocketWrite) == (int)ntohl(enMsg->size));
1539 free(enMsg);
1540 }
1541 else
1542 {
1543 result = false;
1544 }
1545 }
1546 else
1547 {
1548 result = (SendEx(m_hSocket, (const char *)rawMsg, ntohl(rawMsg->size), 0, m_mutexSocketWrite) == (int)ntohl(rawMsg->size));
1549 }
1550 free(rawMsg);
1551
1552 if (!result)
1553 {
1554 closesocket(m_hSocket);
1555 m_hSocket = -1;
1556 }
1557 }
1558
1559 /**
1560 * Send raw message to client
1561 */
1562 void ClientSession::sendRawMessage(NXCP_MESSAGE *msg)
1563 {
1564 TCHAR buffer[128];
1565 debugPrintf(6, _T("Sending raw message %s"), NXCPMessageCodeName(ntohs(msg->code), buffer));
1566
1567 bool result;
1568 if (m_pCtx != NULL)
1569 {
1570 NXCP_ENCRYPTED_MESSAGE *enMsg = m_pCtx->encryptMessage(msg);
1571 if (enMsg != NULL)
1572 {
1573 result = (SendEx(m_hSocket, (char *)enMsg, ntohl(enMsg->size), 0, m_mutexSocketWrite) == (int)ntohl(enMsg->size));
1574 free(enMsg);
1575 }
1576 else
1577 {
1578 result = false;
1579 }
1580 }
1581 else
1582 {
1583 result = (SendEx(m_hSocket, (const char *)msg, ntohl(msg->size), 0, m_mutexSocketWrite) == (int)ntohl(msg->size));
1584 }
1585
1586 if (!result)
1587 {
1588 closesocket(m_hSocket);
1589 m_hSocket = -1;
1590 }
1591 }
1592
1593 /**
1594 * Send file to client
1595 */
1596 BOOL ClientSession::sendFile(const TCHAR *file, UINT32 dwRqId, long ofset)
1597 {
1598 return SendFileOverNXCP(m_hSocket, dwRqId, file, m_pCtx, ofset, NULL, NULL, m_mutexSocketWrite);
1599 }
1600
1601 /**
1602 * Send server information to client
1603 */
1604 void ClientSession::sendServerInfo(UINT32 dwRqId)
1605 {
1606 NXCPMessage msg;
1607 TCHAR szBuffer[1024];
1608 String strURL;
1609
1610 // Prepare response message
1611 msg.setCode(CMD_REQUEST_COMPLETED);
1612 msg.setId(dwRqId);
1613
1614 // Generate challenge for certificate authentication
1615 #ifdef _WITH_ENCRYPTION
1616 RAND_bytes(m_challenge, CLIENT_CHALLENGE_SIZE);
1617 #else
1618 memset(m_challenge, 0, CLIENT_CHALLENGE_SIZE);
1619 #endif
1620
1621 // Fill message with server info
1622 msg.setField(VID_RCC, RCC_SUCCESS);
1623 msg.setField(VID_SERVER_VERSION, NETXMS_VERSION_STRING);
1624 msg.setField(VID_SERVER_ID, (BYTE *)&g_qwServerId, sizeof(QWORD));
1625 msg.setField(VID_SUPPORTED_ENCRYPTION, (UINT32)0);
1626 msg.setField(VID_PROTOCOL_VERSION, (UINT32)CLIENT_PROTOCOL_VERSION);
1627 msg.setField(VID_CHALLENGE, m_challenge, CLIENT_CHALLENGE_SIZE);
1628 msg.setField(VID_TIMESTAMP, (UINT32)time(NULL));
1629
1630 #if defined(_WIN32)
1631 TIME_ZONE_INFORMATION tz;
1632 WCHAR wst[4], wdt[8], *curr;
1633 int i;
1634
1635 DWORD tzType = GetTimeZoneInformation(&tz);
1636
1637 // Create 3 letter abbreviation for standard name
1638 for(i = 0, curr = tz.StandardName; (*curr != 0) && (i < 3); curr++)
1639 if (iswupper(*curr))
1640 wst[i++] = *curr;
1641 while(i < 3)
1642 wst[i++] = L'X';
1643 wst[i] = 0;
1644
1645 // Create abbreviation for DST name
1646 for(i = 0, curr = tz.DaylightName; (*curr != 0) && (i < 7); curr++)
1647 if (iswupper(*curr))
1648 wdt[i++] = *curr;
1649 while(i < 3)
1650 wdt[i++] = L'X';
1651 wdt[i] = 0;
1652
1653 LONG effectiveBias;
1654 switch(tzType)
1655 {
1656 case TIME_ZONE_ID_STANDARD:
1657 effectiveBias = tz.Bias + tz.StandardBias;
1658 break;
1659 case TIME_ZONE_ID_DAYLIGHT:
1660 effectiveBias = tz.Bias + tz.DaylightBias;
1661 break;
1662 case TIME_ZONE_ID_UNKNOWN:
1663 effectiveBias = tz.Bias;
1664 break;
1665 default: // error
1666 effectiveBias = 0;
1667 debugPrintf(4, _T("GetTimeZoneInformation() call failed"));
1668 break;
1669 }
1670
1671 #ifdef UNICODE
1672 swprintf(szBuffer, 1024, L"%s%c%02d%s", wst, (effectiveBias > 0) ? '-' : '+',
1673 abs(effectiveBias) / 60, (tz.DaylightBias != 0) ? wdt : L"");
1674 #else
1675 sprintf(szBuffer, "%S%c%02d%S", wst, (effectiveBias > 0) ? '-' : '+',
1676 abs(effectiveBias) / 60, (tz.DaylightBias != 0) ? wdt : L"");
1677 #endif
1678
1679 #elif HAVE_TM_GMTOFF /* not Windows but have tm_gmtoff */
1680
1681 time_t t = time(NULL);
1682 int gmtOffset;
1683 #if HAVE_LOCALTIME_R
1684 struct tm tmbuff;
1685 struct tm *loc = localtime_r(&t, &tmbuff);
1686 #else
1687 struct tm *loc = localtime(&t);
1688 #endif
1689 gmtOffset = loc->tm_gmtoff / 3600;
1690 #ifdef UNICODE
1691 swprintf(szBuffer, 1024, L"%hs%hc%02d%hs", tzname[0], (gmtOffset >= 0) ? '+' : '-',
1692 abs(gmtOffset), (tzname[1] != NULL) ? tzname[1] : "");
1693 #else
1694 sprintf(szBuffer, "%s%c%02d%s", tzname[0], (gmtOffset >= 0) ? '+' : '-',
1695 abs(gmtOffset), (tzname[1] != NULL) ? tzname[1] : "");
1696 #endif
1697
1698 #else /* not Windows and no tm_gmtoff */
1699
1700 time_t t = time(NULL);
1701 #if HAVE_GMTIME_R
1702 struct tm tmbuff;
1703 struct tm *gmt = gmtime_r(&t, &tmbuff);
1704 #else
1705 struct tm *gmt = gmtime(&t);
1706 #endif
1707 gmt->tm_isdst = -1;
1708 int gmtOffset = (int)((t - mktime(gmt)) / 3600);
1709 #ifdef UNICODE
1710 swprintf(szBuffer, 1024, L"%hs%hc%02d%hs", tzname[0], (gmtOffset >= 0) ? '+' : '-',
1711 abs(gmtOffset), (tzname[1] != NULL) ? tzname[1] : "");
1712 #else
1713 sprintf(szBuffer, "%s%c%02d%s", tzname[0], (gmtOffset >= 0) ? '+' : '-',
1714 abs(gmtOffset), (tzname[1] != NULL) ? tzname[1] : "");
1715 #endif
1716
1717 #endif
1718
1719 msg.setField(VID_TIMEZONE, szBuffer);
1720 debugPrintf(2, _T("Server time zone: %s"), szBuffer);
1721
1722 ConfigReadStr(_T("TileServerURL"), szBuffer, 1024, _T("http://tile.openstreetmap.org/"));
1723 msg.setField(VID_TILE_SERVER_URL, szBuffer);
1724
1725 ConfigReadStr(_T("DefaultConsoleDateFormat"), szBuffer, 1024, _T("dd.MM.yyyy"));
1726 msg.setField(VID_DATE_FORMAT, szBuffer);
1727
1728 ConfigReadStr(_T("DefaultConsoleTimeFormat"), szBuffer, 1024, _T("HH:mm:ss"));
1729 msg.setField(VID_TIME_FORMAT, szBuffer);
1730
1731 ConfigReadStr(_T("DefaultConsoleShortTimeFormat"), szBuffer, 1024, _T("HH:mm"));
1732 msg.setField(VID_SHORT_TIME_FORMAT, szBuffer);
1733
1734 // Send response
1735 sendMessage(&msg);
1736 }
1737
1738 /**
1739 * Authenticate client
1740 */
1741 void ClientSession::login(NXCPMessage *pRequest)
1742 {
1743 NXCPMessage msg;
1744 TCHAR szLogin[MAX_USER_NAME], szPassword[1024];
1745 int nAuthType;
1746 bool changePasswd = false, intruderLockout = false;
1747 UINT32 dwResult;
1748 #ifdef _WITH_ENCRYPTION
1749 X509 *pCert;
1750 #endif
1751
1752 // Prepare response message
1753 msg.setCode(CMD_LOGIN_RESP);
1754 msg.setId(pRequest->getId());
1755
1756 // Get client info string
1757 if (pRequest->isFieldExist(VID_CLIENT_INFO))
1758 {
1759 TCHAR szClientInfo[32], szOSInfo[32], szLibVersion[16];
1760
1761 pRequest->getFieldAsString(VID_CLIENT_INFO, szClientInfo, 32);
1762 pRequest->getFieldAsString(VID_OS_INFO, szOSInfo, 32);
1763 pRequest->getFieldAsString(VID_LIBNXCL_VERSION, szLibVersion, 16);
1764 _sntprintf(m_szClientInfo, 96, _T("%s (%s; libnxcl %s)"),
1765 szClientInfo, szOSInfo, szLibVersion);
1766 }
1767
1768 m_clientType = pRequest->getFieldAsUInt16(VID_CLIENT_TYPE);
1769 if ((m_clientType < 0) || (m_clientType > CLIENT_TYPE_APPLICATION))
1770 m_clientType = CLIENT_TYPE_DESKTOP;
1771
1772 if (m_clientType == CLIENT_TYPE_WEB)
1773 {
1774 _tcscpy(m_webServerAddress, m_workstation);
1775 if (pRequest->isFieldExist(VID_CLIENT_ADDRESS))
1776 {
1777 pRequest->getFieldAsString(VID_CLIENT_ADDRESS, m_workstation, 256);
1778 debugPrintf(5, _T("Real web client address is %s"), m_workstation);
1779 }
1780 }
1781
1782 if (pRequest->isFieldExist(VID_LANGUAGE))
1783 {
1784 pRequest->getFieldAsString(VID_LANGUAGE, m_language, 8);
1785 }
1786
1787 if (!(m_dwFlags & CSF_AUTHENTICATED))
1788 {
1789 pRequest->getFieldAsString(VID_LOGIN_NAME, szLogin, MAX_USER_NAME);
1790 nAuthType = (int)pRequest->getFieldAsUInt16(VID_AUTH_TYPE);
1791 debugPrintf(6, _T("authentication type %d"), nAuthType);
1792 switch(nAuthType)
1793 {
1794 case NETXMS_AUTH_TYPE_PASSWORD:
1795 #ifdef UNICODE
1796 pRequest->getFieldAsString(VID_PASSWORD, szPassword, 256);
1797 #else
1798 pRequest->getFieldAsUtf8String(VID_PASSWORD, szPassword, 1024);
1799 #endif
1800 dwResult = AuthenticateUser(szLogin, szPassword, 0, NULL, NULL, &m_dwUserId,
1801 &m_dwSystemAccess, &changePasswd, &intruderLockout, false);
1802 break;
1803 case NETXMS_AUTH_TYPE_CERTIFICATE:
1804 #ifdef _WITH_ENCRYPTION
1805 pCert = CertificateFromLoginMessage(pRequest);
1806 if (pCert != NULL)
1807 {
1808 BYTE signature[256];
1809 UINT32 dwSigLen;
1810
1811 dwSigLen = pRequest->getFieldAsBinary(VID_SIGNATURE, signature, 256);
1812 dwResult = AuthenticateUser(szLogin, (TCHAR *)signature, dwSigLen, pCert,
1813 m_challenge, &m_dwUserId, &m_dwSystemAccess,
1814 &changePasswd, &intruderLockout, false);
1815 X509_free(pCert);
1816 }
1817 else
1818 {
1819 dwResult = RCC_BAD_CERTIFICATE;
1820 }
1821 #else
1822 dwResult = RCC_NOT_IMPLEMENTED;
1823 #endif
1824 break;
1825 case NETXMS_AUTH_TYPE_SSO_TICKET:
1826 char ticket[1024];
1827 pRequest->getFieldAsMBString(VID_PASSWORD, ticket, 1024);
1828 if (CASAuthenticate(ticket, szLogin))
1829 {
1830 debugPrintf(5, _T("SSO ticket %hs is valid, login name %s"), ticket, szLogin);
1831 dwResult = AuthenticateUser(szLogin, NULL, 0, NULL, NULL, &m_dwUserId,
1832 &m_dwSystemAccess, &changePasswd, &intruderLockout, true);
1833 }
1834 else
1835 {
1836 debugPrintf(5, _T("SSO ticket %hs is invalid"), ticket);
1837 dwResult = RCC_ACCESS_DENIED;
1838 }
1839 break;
1840 default:
1841 dwResult = RCC_UNSUPPORTED_AUTH_TYPE;
1842 break;
1843 }
1844
1845 // Additional validation by loaded modules
1846 if (dwResult == RCC_SUCCESS)
1847 {
1848 for(UINT32 i = 0; i < g_dwNumModules; i++)
1849 {
1850 if (g_pModuleList[i].pfAdditionalLoginCheck != NULL)
1851 {
1852 dwResult = g_pModuleList[i].pfAdditionalLoginCheck(m_dwUserId, pRequest);
1853 if (dwResult != RCC_SUCCESS)
1854 {
1855 debugPrintf(4, _T("Login blocked by module %s (rcc=%d)"), g_pModuleList[i].szName, dwResult);
1856 break;
1857 }
1858 }
1859 }
1860 }
1861
1862 if (dwResult == RCC_SUCCESS)
1863 {
1864 m_dwFlags |= CSF_AUTHENTICATED;
1865 _sntprintf(m_szUserName, MAX_SESSION_NAME, _T("%s@%s"), szLogin, m_workstation);
1866 m_loginTime = time(NULL);
1867 msg.setField(VID_RCC, RCC_SUCCESS);
1868 msg.setField(VID_USER_SYS_RIGHTS, m_dwSystemAccess);
1869 msg.setField(VID_USER_ID, m_dwUserId);
1870 msg.setField(VID_SESSION_ID, (UINT32)m_id);
1871 msg.setField(VID_CHANGE_PASSWD_FLAG, (WORD)changePasswd);
1872 msg.setField(VID_DBCONN_STATUS, (UINT16)((g_flags & AF_DB_CONNECTION_LOST) ? 0 : 1));
1873 msg.setField(VID_ZONING_ENABLED, (UINT16)((g_flags & AF_ENABLE_ZONING) ? 1 : 0));
1874 msg.setField(VID_POLLING_INTERVAL, ConfigReadULong(_T("DefaultDCIPollingInterval"), 60));
1875 msg.setField(VID_RETENTION_TIME, ConfigReadULong(_T("DefaultDCIRetentionTime"), 30));
1876 msg.setField(VID_ALARM_STATUS_FLOW_STATE, (UINT16)ConfigReadInt(_T("StrictAlarmStatusFlow"), 0));
1877 msg.setField(VID_TIMED_ALARM_ACK_ENABLED, (UINT16)ConfigReadInt(_T("EnableTimedAlarmAck"), 0));
1878 msg.setField(VID_VIEW_REFRESH_INTERVAL, (UINT16)ConfigReadInt(_T("MinViewRefreshInterval"), 200));
1879 msg.setField(VID_HELPDESK_LINK_ACTIVE, (UINT16)((g_flags & AF_HELPDESK_LINK_ACTIVE) ? 1 : 0));
1880 msg.setField(VID_ALARM_LIST_DISP_LIMIT, ConfigReadULong(_T("AlarmListDisplayLimit"), 4096));
1881 debugPrintf(3, _T("User %s authenticated (language=%s clientInfo=\"%s\")"), m_szUserName, m_language, m_szClientInfo);
1882 WriteAuditLog(AUDIT_SECURITY, TRUE, m_dwUserId, m_workstation, m_id, 0,
1883 _T("User \"%s\" logged in (language: %s; client info: %s)"), szLogin, m_language, m_szClientInfo);
1884 }
1885 else
1886 {
1887 msg.setField(VID_RCC, dwResult);
1888 WriteAuditLog(AUDIT_SECURITY, FALSE, m_dwUserId, m_workstation, m_id, 0,
1889 _T("User \"%s\" login failed with error code %d (client info: %s)"),
1890 szLogin, dwResult, m_szClientInfo);
1891 if (intruderLockout)
1892 {
1893 WriteAuditLog(AUDIT_SECURITY, FALSE, m_dwUserId, m_workstation, m_id, 0,
1894 _T("User account \"%s\" temporary disabled due to excess count of failed authentication attempts"), szLogin);
1895 }
1896 }
1897 }
1898 else
1899 {
1900 msg.setField(VID_RCC, RCC_OUT_OF_STATE_REQUEST);
1901 }
1902
1903 // Send response
1904 sendMessage(&msg);
1905 }
1906
1907 /**
1908 * Send event configuration to client
1909 */
1910 void ClientSession::sendEventDB(UINT32 dwRqId)
1911 {
1912 DB_ASYNC_RESULT hResult;
1913 NXCPMessage msg;
1914 TCHAR szBuffer[4096];
1915
1916 // Prepare response message
1917 msg.setCode(CMD_REQUEST_COMPLETED);
1918 msg.setId(dwRqId);
1919
1920 if (checkSysAccessRights(SYSTEM_ACCESS_VIEW_EVENT_DB) || checkSysAccessRights(SYSTEM_ACCESS_EDIT_EVENT_DB) || checkSysAccessRights(SYSTEM_ACCESS_EPP))
1921 {
1922 if (!(g_flags & AF_DB_CONNECTION_LOST))
1923 {
1924 msg.setField(VID_RCC, RCC_SUCCESS);
1925 sendMessage(&msg);
1926 msg.deleteAllFields();
1927
1928 // Prepare data message
1929 msg.setCode(CMD_EVENT_DB_RECORD);
1930 msg.setId(dwRqId);
1931
1932 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
1933 hResult = DBAsyncSelect(hdb, _T("SELECT event_code,event_name,severity,flags,message,description FROM event_cfg"));
1934 if (hResult != NULL)
1935 {
1936 while(DBFetch(hResult))
1937 {
1938 msg.setField(VID_EVENT_CODE, DBGetFieldAsyncULong(hResult, 0));
1939 msg.setField(VID_NAME, DBGetFieldAsync(hResult, 1, szBuffer, 1024));
1940 msg.setField(VID_SEVERITY, DBGetFieldAsyncULong(hResult, 2));
1941 msg.setField(VID_FLAGS, DBGetFieldAsyncULong(hResult, 3));
1942
1943 DBGetFieldAsync(hResult, 4, szBuffer, 4096);
1944 msg.setField(VID_MESSAGE, szBuffer);
1945
1946 DBGetFieldAsync(hResult, 5, szBuffer, 4096);
1947 msg.setField(VID_DESCRIPTION, szBuffer);
1948
1949 sendMessage(&msg);
1950 msg.deleteAllFields();
1951 }
1952 DBFreeAsyncResult(hResult);
1953 }
1954 DBConnectionPoolReleaseConnection(hdb);
1955
1956 // End-of-list indicator
1957 msg.setField(VID_EVENT_CODE, (UINT32)0);
1958 msg.setEndOfSequence();
1959 }
1960 else
1961 {
1962 msg.setField(VID_RCC, RCC_DB_CONNECTION_LOST);
1963 }
1964 }
1965 else
1966 {
1967 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
1968 }
1969 sendMessage(&msg);
1970 }
1971
1972 /**
1973 * Callback for sending event configuration change notifications
1974 */
1975 static void SendEventDBChangeNotification(ClientSession *session, void *arg)
1976 {
1977 if (session->isAuthenticated() &&
1978 (session->checkSysAccessRights(SYSTEM_ACCESS_VIEW_EVENT_DB) ||
1979 session->checkSysAccessRights(SYSTEM_ACCESS_EDIT_EVENT_DB) ||
1980 session->checkSysAccessRights(SYSTEM_ACCESS_EPP)))
1981 session->postMessage((NXCPMessage *)arg);
1982 }
1983
1984 /**
1985 * Update event template
1986 */
1987 void ClientSession::modifyEventTemplate(NXCPMessage *pRequest)
1988 {
1989 NXCPMessage msg;
1990
1991 // Prepare reply message
1992 msg.setCode(CMD_REQUEST_COMPLETED);
1993 msg.setId(pRequest->getId());
1994
1995 // Check access rights
1996 if (checkSysAccessRights(SYSTEM_ACCESS_EDIT_EVENT_DB))
1997 {
1998 TCHAR szQuery[8192], szName[MAX_EVENT_NAME];
1999
2000 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
2001
2002 // Check if event with specific code exists
2003 UINT32 dwEventCode = pRequest->getFieldAsUInt32(VID_EVENT_CODE);
2004 bool bEventExist = IsDatabaseRecordExist(hdb, _T("event_cfg"), _T("event_code"), dwEventCode);
2005
2006 // Check that we are not trying to create event below 100000
2007 if (bEventExist || (dwEventCode >= FIRST_USER_EVENT_ID))
2008 {
2009 // Prepare and execute SQL query
2010 pRequest->getFieldAsString(VID_NAME, szName, MAX_EVENT_NAME);
2011 if (IsValidObjectName(szName))
2012 {
2013 TCHAR szMessage[MAX_EVENT_MSG_LENGTH], *pszDescription;
2014
2015 pRequest->getFieldAsString(VID_MESSAGE, szMessage, MAX_EVENT_MSG_LENGTH);
2016 pszDescription = pRequest->getFieldAsString(VID_DESCRIPTION);
2017
2018 if (bEventExist)
2019 {
2020 _sntprintf(szQuery, sizeof(szQuery) / sizeof(TCHAR), _T("UPDATE event_cfg SET event_name='%s',severity=%d,flags=%d,message=%s,description=%s WHERE event_code=%d"),
2021 szName, pRequest->getFieldAsUInt32(VID_SEVERITY), pRequest->getFieldAsUInt32(VID_FLAGS),
2022 (const TCHAR *)DBPrepareString(g_hCoreDB, szMessage),
2023 (const TCHAR *)DBPrepareString(g_hCoreDB, pszDescription), dwEventCode);
2024 }
2025 else
2026 {
2027 _sntprintf(szQuery, sizeof(szQuery) / sizeof(TCHAR), _T("INSERT INTO event_cfg (event_code,event_name,severity,flags,")
2028 _T("message,description) VALUES (%d,'%s',%d,%d,%s,%s)"),
2029 dwEventCode, szName, pRequest->getFieldAsUInt32(VID_SEVERITY),
2030 pRequest->getFieldAsUInt32(VID_FLAGS), (const TCHAR *)DBPrepareString(g_hCoreDB, szMessage),
2031 (const TCHAR *)DBPrepareString(g_hCoreDB, pszDescription));
2032 }
2033
2034 safe_free(pszDescription);
2035
2036 if (DBQuery(hdb, szQuery))
2037 {
2038 msg.setField(VID_RCC, RCC_SUCCESS);
2039 ReloadEvents();
2040 NotifyClientSessions(NX_NOTIFY_EVENTDB_CHANGED, 0);
2041
2042 NXCPMessage nmsg(pRequest);
2043 nmsg.setCode(CMD_EVENT_DB_UPDATE);
2044 nmsg.setField(VID_NOTIFICATION_CODE, (WORD)NX_NOTIFY_ETMPL_CHANGED);
2045 EnumerateClientSessions(SendEventDBChangeNotification, &nmsg);
2046 }
2047 else
2048 {
2049 msg.setField(VID_RCC, RCC_DB_FAILURE);
2050 }
2051 }
2052 else
2053 {
2054 msg.setField(VID_RCC, RCC_INVALID_OBJECT_NAME);
2055 }
2056 }
2057 else
2058 {
2059 msg.setField(VID_RCC, RCC_INVALID_EVENT_CODE);
2060 }
2061 DBConnectionPoolReleaseConnection(hdb);
2062 }
2063 else
2064 {
2065 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
2066 }
2067
2068 // Send response
2069 sendMessage(&msg);
2070 }
2071
2072 /**
2073 * Delete event template
2074 */
2075 void ClientSession::deleteEventTemplate(NXCPMessage *pRequest)
2076 {
2077 NXCPMessage msg;
2078 UINT32 dwEventCode;
2079
2080 // Prepare reply message
2081 msg.setCode(CMD_REQUEST_COMPLETED);
2082 msg.setId(pRequest->getId());
2083
2084 dwEventCode = pRequest->getFieldAsUInt32(VID_EVENT_CODE);
2085
2086 // Check access rights
2087 if (checkSysAccessRights(SYSTEM_ACCESS_EDIT_EVENT_DB) && (dwEventCode >= FIRST_USER_EVENT_ID))
2088 {
2089 TCHAR szQuery[256];
2090
2091 _sntprintf(szQuery, 256, _T("DELETE FROM event_cfg WHERE event_code=%d"), dwEventCode);
2092 if (DBQuery(g_hCoreDB, szQuery))
2093 {
2094 DeleteEventTemplateFromList(dwEventCode);
2095 NotifyClientSessions(NX_NOTIFY_EVENTDB_CHANGED, 0);
2096
2097 NXCPMessage nmsg;
2098 nmsg.setCode(CMD_EVENT_DB_UPDATE);
2099 nmsg.setField(VID_NOTIFICATION_CODE, (WORD)NX_NOTIFY_ETMPL_DELETED);
2100 nmsg.setField(VID_EVENT_CODE, dwEventCode);
2101 EnumerateClientSessions(SendEventDBChangeNotification, &nmsg);
2102
2103 msg.setField(VID_RCC, RCC_SUCCESS);
2104
2105 WriteAuditLog(AUDIT_SYSCFG, TRUE, m_dwUserId, m_workstation, m_id, 0, _T("Event template %d deleted"), dwEventCode);
2106 }
2107 else
2108 {
2109 msg.setField(VID_RCC, RCC_DB_FAILURE);
2110 }
2111 }
2112 else
2113 {
2114 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
2115 }
2116
2117 // Send response
2118 sendMessage(&msg);
2119 }
2120
2121 /**
2122 * Generate event code for new event template
2123 */
2124 void ClientSession::generateEventCode(UINT32 dwRqId)
2125 {
2126 NXCPMessage msg;
2127
2128 // Prepare reply message
2129 msg.setCode(CMD_REQUEST_COMPLETED);
2130 msg.setId(dwRqId);
2131
2132 // Check access rights
2133 if (checkSysAccessRights(SYSTEM_ACCESS_EDIT_EVENT_DB))
2134 {
2135 msg.setField(VID_EVENT_CODE, CreateUniqueId(IDG_EVENT));
2136 }
2137 else
2138 {
2139 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
2140 }
2141
2142 // Send response
2143 sendMessage(&msg);
2144 }
2145
2146 /**
2147 * Send all objects to client
2148 */
2149 void ClientSession::sendAllObjects(NXCPMessage *pRequest)
2150 {
2151 NXCPMessage msg;
2152
2153 // Send confirmation message
2154 msg.setCode(CMD_REQUEST_COMPLETED);
2155 msg.setId(pRequest->getId());
2156 msg.setField(VID_RCC, RCC_SUCCESS);
2157 sendMessage(&msg);
2158 msg.deleteAllFields();
2159
2160 // Change "sync comments" flag
2161 if (pRequest->getFieldAsUInt16(VID_SYNC_COMMENTS))
2162 m_dwFlags |= CSF_SYNC_OBJECT_COMMENTS;
2163 else
2164 m_dwFlags &= ~CSF_SYNC_OBJECT_COMMENTS;
2165
2166 // Get client's last known time stamp
2167 UINT32 dwTimeStamp = pRequest->getFieldAsUInt32(VID_TIMESTAMP);
2168
2169 // Prepare message
2170 msg.setCode(CMD_OBJECT);
2171
2172 // Send objects, one per message
2173 ObjectArray<NetObj> *objects = g_idxObjectById.getObjects(true);
2174 MutexLock(m_mutexSendObjects);
2175 for(int i = 0; i < objects->size(); i++)
2176 {
2177 NetObj *object = objects->get(i);
2178 if (object->checkAccessRights(m_dwUserId, OBJECT_ACCESS_READ) &&
2179 (object->getTimeStamp() >= dwTimeStamp) &&
2180 !object->isHidden() && !object->isSystem())
2181 {
2182 object->fillMessage(&msg);
2183 if (m_dwFlags & CSF_SYNC_OBJECT_COMMENTS)
2184 object->commentsToMessage(&msg);
2185 if (!object->checkAccessRights(m_dwUserId, OBJECT_ACCESS_MODIFY))
2186 {
2187 // mask passwords
2188 msg.setField(VID_SHARED_SECRET, _T("********"));
2189 msg.setField(VID_SNMP_AUTH_PASSWORD, _T("********"));
2190 msg.setField(VID_SNMP_PRIV_PASSWORD, _T("********"));
2191 }
2192 sendMessage(&msg);
2193 msg.deleteAllFields();
2194 }
2195 object->decRefCount();
2196 }
2197 delete objects;
2198
2199 // Send end of list notification
2200 msg.setCode(CMD_OBJECT_LIST_END);
2201 sendMessage(&msg);
2202
2203 MutexUnlock(m_mutexSendObjects);
2204 }
2205
2206 /**
2207 * Send selected objects to client
2208 */
2209 void ClientSession::sendSelectedObjects(NXCPMessage *pRequest)
2210 {
2211 NXCPMessage msg;
2212
2213 // Send confirmation message
2214 msg.setCode(CMD_REQUEST_COMPLETED);
2215 msg.setId(pRequest->getId());
2216 msg.setField(VID_RCC, RCC_SUCCESS);
2217 sendMessage(&msg);
2218 msg.deleteAllFields();
2219
2220 // Change "sync comments" flag
2221 if (pRequest->getFieldAsBoolean(VID_SYNC_COMMENTS))
2222 m_dwFlags |= CSF_SYNC_OBJECT_COMMENTS;
2223 else
2224 m_dwFlags &= ~CSF_SYNC_OBJECT_COMMENTS;
2225
2226 UINT32 dwTimeStamp = pRequest->getFieldAsUInt32(VID_TIMESTAMP);
2227 UINT32 numObjects = pRequest->getFieldAsUInt32(VID_NUM_OBJECTS);
2228 UINT32 *objects = (UINT32 *)malloc(sizeof(UINT32) * numObjects);
2229 pRequest->getFieldAsInt32Array(VID_OBJECT_LIST, numObjects, objects);
2230 UINT32 options = pRequest->getFieldAsUInt16(VID_FLAGS);
2231
2232 MutexLock(m_mutexSendObjects);
2233
2234 // Prepare message
2235 msg.setCode((options & OBJECT_SYNC_SEND_UPDATES) ? CMD_OBJECT_UPDATE : CMD_OBJECT);
2236
2237 // Send objects, one per message
2238 for(UINT32 i = 0; i < numObjects; i++)
2239 {
2240 NetObj *object = FindObjectById(objects[i]);
2241 if ((object != NULL) &&
2242 object->checkAccessRights(m_dwUserId, OBJECT_ACCESS_READ) &&
2243 (object->getTimeStamp() >= dwTimeStamp) &&
2244 !object->isHidden() && !object->isSystem())
2245 {
2246 object->fillMessage(&msg);
2247 if (m_dwFlags & CSF_SYNC_OBJECT_COMMENTS)
2248 object->commentsToMessage(&msg);
2249 if (!object->checkAccessRights(m_dwUserId, OBJECT_ACCESS_MODIFY))
2250 {
2251 // mask passwords
2252 msg.setField(VID_SHARED_SECRET, _T("********"));
2253 msg.setField(VID_SNMP_AUTH_PASSWORD, _T("********"));
2254 msg.setField(VID_SNMP_PRIV_PASSWORD, _T("********"));
2255 }
2256 sendMessage(&msg);
2257 msg.deleteAllFields();
2258 }
2259 }
2260
2261 MutexUnlock(m_mutexSendObjects);
2262 safe_free(objects);
2263
2264 if (options & OBJECT_SYNC_DUAL_CONFIRM)
2265 {
2266 msg.setCode(CMD_REQUEST_COMPLETED);
2267 msg.setField(VID_RCC, RCC_SUCCESS);
2268 sendMessage(&msg);
2269 }
2270 }
2271
2272 /**
2273 * Send event log records to client
2274 */
2275 void ClientSession::sendEventLog(NXCPMessage *pRequest)
2276 {
2277 NXCPMessage msg;
2278 DB_ASYNC_RESULT hResult = NULL;
2279 DB_RESULT hTempResult;
2280 UINT32 dwRqId, dwMaxRecords, dwNumRows, dwId;
2281 TCHAR szQuery[1024], szBuffer[1024];
2282 WORD wRecOrder;
2283
2284 dwRqId = pRequest->getId();
2285 dwMaxRecords = pRequest->getFieldAsUInt32(VID_MAX_RECORDS);
2286 wRecOrder = ((g_dbSyntax == DB_SYNTAX_MSSQL) || (g_dbSyntax == DB_SYNTAX_ORACLE)) ? RECORD_ORDER_REVERSED : RECORD_ORDER_NORMAL;
2287
2288 // Prepare confirmation message
2289 msg.setCode(CMD_REQUEST_COMPLETED);
2290 msg.setId(dwRqId);
2291
2292 MutexLock(m_mutexSendEvents);
2293 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
2294
2295 // Retrieve events from database
2296 switch(g_dbSyntax)
2297 {
2298 case DB_SYNTAX_MYSQL:
2299 case DB_SYNTAX_PGSQL:
2300 case DB_SYNTAX_SQLITE:
2301 dwNumRows = 0;
2302 hTempResult = DBSelect(hdb, _T("SELECT count(*) FROM event_log"));
2303 if (hTempResult != NULL)
2304 {
2305 if (DBGetNumRows(hTempResult) > 0)
2306 {
2307 dwNumRows = DBGetFieldULong(hTempResult, 0, 0);
2308 }
2309 DBFreeResult(hTempResult);
2310 }
2311 _sntprintf(szQuery, 1024,
2312 _T("SELECT event_id,event_code,event_timestamp,event_source,")
2313 _T("event_severity,event_message,user_tag FROM event_log ")
2314 _T("ORDER BY event_id LIMIT %u OFFSET %u"),
2315 dwMaxRecords, dwNumRows - min(dwNumRows, dwMaxRecords));
2316 break;
2317 case DB_SYNTAX_MSSQL:
2318 _sntprintf(szQuery, 1024,
2319 _T("SELECT TOP %u event_id,event_code,event_timestamp,event_source,")
2320 _T("event_severity,event_message,user_tag FROM event_log ")
2321 _T("ORDER BY event_id DESC"), dwMaxRecords);
2322 break;
2323 case DB_SYNTAX_ORACLE:
2324 _sntprintf(szQuery, 1024,
2325 _T("SELECT event_id,event_code,event_timestamp,event_source,")
2326 _T("event_severity,event_message,user_tag FROM event_log ")
2327 _T("WHERE ROWNUM <= %u ORDER BY event_id DESC"), dwMaxRecords);
2328 break;
2329 case DB_SYNTAX_DB2:
2330 _sntprintf(szQuery, 1024,
2331 _T("SELECT event_id,event_code,event_timestamp,event_source,")
2332 _T("event_severity,event_message,user_tag FROM event_log ")
2333 _T("ORDER BY event_id DESC FETCH FIRST %u ROWS ONLY"), dwMaxRecords);
2334 break;
2335 default:
2336 szQuery[0] = 0;
2337 break;
2338 }
2339 hResult = DBAsyncSelect(hdb, szQuery);
2340 if (hResult != NULL)
2341 {
2342 msg.setField(VID_RCC, RCC_SUCCESS);
2343 sendMessage(&msg);
2344 msg.deleteAllFields();
2345 msg.setCode(CMD_EVENTLOG_RECORDS);
2346
2347 for(dwId = VID_EVENTLOG_MSG_BASE, dwNumRows = 0; DBFetch(hResult); dwNumRows++)
2348 {
2349 if (dwNumRows == 10)
2350 {
2351 msg.setField(VID_NUM_RECORDS, dwNumRows);
2352 msg.setField(VID_RECORDS_ORDER, wRecOrder);
2353 sendMessage(&msg);
2354 msg.deleteAllFields();
2355 dwNumRows = 0;
2356 dwId = VID_EVENTLOG_MSG_BASE;
2357 }
2358 msg.setField(dwId++, DBGetFieldAsyncUInt64(hResult, 0));
2359 msg.setField(dwId++, DBGetFieldAsyncULong(hResult, 1));
2360 msg.setField(dwId++, DBGetFieldAsyncULong(hResult, 2));
2361 msg.setField(dwId++, DBGetFieldAsyncULong(hResult, 3));
2362 msg.setField(dwId++, (WORD)DBGetFieldAsyncLong(hResult, 4));
2363 DBGetFieldAsync(hResult, 5, szBuffer, 1024);
2364 msg.setField(dwId++, szBuffer);
2365 DBGetFieldAsync(hResult, 6, szBuffer, 1024);
2366 msg.setField(dwId++, szBuffer);
2367 msg.setField(dwId++, (UINT32)0); // Do not send parameters
2368 }
2369 DBFreeAsyncResult(hResult);
2370
2371 // Send remaining records with End-Of-Sequence notification
2372 msg.setField(VID_NUM_RECORDS, dwNumRows);
2373 msg.setField(VID_RECORDS_ORDER, wRecOrder);
2374 msg.setEndOfSequence();
2375 sendMessage(&msg);
2376 }
2377 else
2378 {
2379 msg.setField(VID_RCC, RCC_DB_FAILURE);
2380 sendMessage(&msg);
2381 }
2382
2383 DBConnectionPoolReleaseConnection(hdb);
2384 MutexUnlock(m_mutexSendEvents);
2385 }
2386
2387 /**
2388 * Send all configuration variables to client
2389 */
2390 void ClientSession::sendAllConfigVars(UINT32 dwRqId)
2391 {
2392 UINT32 i, dwId, dwNumRecords;
2393 NXCPMessage msg;
2394 DB_RESULT hResult;
2395 TCHAR szBuffer[MAX_DB_STRING];
2396
2397 // Prepare message
2398 msg.setCode(CMD_REQUEST_COMPLETED);
2399 msg.setId(dwRqId);
2400
2401 // Check user rights
2402 if ((m_dwUserId == 0) || (m_dwSystemAccess & SYSTEM_ACCESS_SERVER_CONFIG))
2403 {
2404 // Retrieve configuration variables from database
2405 hResult = DBSelect(g_hCoreDB, _T("SELECT var_name,var_value,need_server_restart FROM config WHERE is_visible=1"));
2406 if (hResult != NULL)
2407 {
2408 // Send events, one per message
2409 dwNumRecords = DBGetNumRows(hResult);
2410 msg.setField(VID_NUM_VARIABLES, dwNumRecords);
2411 for(i = 0, dwId = VID_VARLIST_BASE; i < dwNumRecords; i++)
2412 {
2413 msg.setField(dwId++, DBGetField(hResult, i, 0, szBuffer, MAX_DB_STRING));
2414 DBGetField(hResult, i, 1, szBuffer, MAX_DB_STRING);
2415 DecodeSQLString(szBuffer);
2416 msg.setField(dwId++, szBuffer);
2417 msg.setField(dwId++, (WORD)DBGetFieldLong(hResult, i, 2));
2418 }
2419 DBFreeResult(hResult);
2420 }
2421 msg.setField(VID_RCC, RCC_SUCCESS);
2422 }
2423 else
2424 {
2425 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
2426 }
2427
2428 // Send response
2429 sendMessage(&msg);
2430 }
2431
2432 /**
2433 * Set configuration variable's value
2434 */
2435 void ClientSession::setConfigVariable(NXCPMessage *pRequest)
2436 {
2437 NXCPMessage msg;
2438 TCHAR szName[MAX_OBJECT_NAME], szValue[MAX_DB_STRING];
2439
2440 // Prepare response message
2441 msg.setCode(CMD_REQUEST_COMPLETED);
2442 msg.setId(pRequest->getId());
2443
2444 // Check user rights
2445 if ((m_dwUserId == 0) || (m_dwSystemAccess & SYSTEM_ACCESS_SERVER_CONFIG))
2446 {
2447 pRequest->getFieldAsString(VID_NAME, szName, MAX_OBJECT_NAME);
2448 pRequest->getFieldAsString(VID_VALUE, szValue, MAX_DB_STRING);
2449 if (ConfigWriteStr(szName, szValue, TRUE))
2450 {
2451 msg.setField(VID_RCC, RCC_SUCCESS);
2452 WriteAuditLog(AUDIT_SYSCFG, TRUE, m_dwUserId, m_workstation, m_id, 0,
2453 _T("Server configuration variable \"%s\" set to \"%s\""), szName, szValue);
2454 }
2455 else
2456 {
2457 msg.setField(VID_RCC, RCC_DB_FAILURE);
2458 }
2459 }
2460 else
2461 {
2462 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
2463 }
2464
2465 // Send response
2466 sendMessage(&msg);
2467 }
2468
2469 /**
2470 * Delete configuration variable
2471 */
2472 void ClientSession::deleteConfigVariable(NXCPMessage *pRequest)
2473 {
2474 NXCPMessage msg;
2475
2476 // Prepare response message
2477 msg.setCode(CMD_REQUEST_COMPLETED);
2478 msg.setId(pRequest->getId());
2479
2480 // Check user rights
2481 if ((m_dwUserId == 0) || (m_dwSystemAccess & SYSTEM_ACCESS_SERVER_CONFIG))
2482 {
2483 TCHAR name[MAX_OBJECT_NAME];
2484 pRequest->getFieldAsString(VID_NAME, name, MAX_OBJECT_NAME);
2485 if (ConfigDelete(name))
2486 {
2487 msg.setField(VID_RCC, RCC_SUCCESS);
2488 WriteAuditLog(AUDIT_SYSCFG, TRUE, m_dwUserId, m_workstation, m_id, 0, _T("Server configuration variable \"%s\" deleted"), name);
2489 }
2490 else
2491 {
2492 msg.setField(VID_RCC, RCC_DB_FAILURE);
2493 }
2494 }
2495 else
2496 {
2497 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
2498 }
2499
2500 // Send response
2501 sendMessage(&msg);
2502 }
2503
2504 /**
2505 * Set configuration clob
2506 */
2507 void ClientSession::setConfigCLOB(NXCPMessage *pRequest)
2508 {
2509 NXCPMessage msg;
2510 TCHAR name[MAX_OBJECT_NAME], *value;
2511
2512 msg.setId(pRequest->getId());
2513 msg.setCode(CMD_REQUEST_COMPLETED);
2514
2515 if (m_dwSystemAccess & SYSTEM_ACCESS_SERVER_CONFIG)
2516 {
2517 pRequest->getFieldAsString(VID_NAME, name, MAX_OBJECT_NAME);
2518 value = pRequest->getFieldAsString(VID_VALUE);
2519 if (value != NULL)
2520 {
2521 if (ConfigWriteCLOB(name, value, TRUE))
2522 {
2523 msg.setField(VID_RCC, RCC_SUCCESS);
2524 WriteAuditLog(AUDIT_SYSCFG, TRUE, m_dwUserId, m_workstation, m_id, 0,
2525 _T("Server configuration variable \"%s\" set to \"%s\""), name, value);
2526 free(value);
2527 }
2528 else
2529 {
2530 msg.setField(VID_RCC, RCC_DB_FAILURE);
2531 }
2532 }
2533 else
2534 {
2535 msg.setField(VID_RCC, RCC_INVALID_REQUEST);
2536 }
2537 }
2538 else
2539 {
2540 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
2541 }
2542
2543 sendMessage(&msg);
2544 }
2545
2546 /**
2547 * Get value of configuration clob
2548 */
2549 void ClientSession::getConfigCLOB(NXCPMessage *pRequest)
2550 {
2551 NXCPMessage msg;
2552 TCHAR name[MAX_OBJECT_NAME], *value;
2553
2554 msg.setId(pRequest->getId());
2555 msg.setCode(CMD_REQUEST_COMPLETED);
2556
2557 if (m_dwSystemAccess & SYSTEM_ACCESS_SERVER_CONFIG)
2558 {
2559 pRequest->getFieldAsString(VID_NAME, name, MAX_OBJECT_NAME);
2560 value = ConfigReadCLOB(name, NULL);
2561 if (value != NULL)
2562 {
2563 msg.setField(VID_VALUE, value);
2564 msg.setField(VID_RCC, RCC_SUCCESS);
2565 free(value);
2566 }
2567 else
2568 {
2569 msg.setField(VID_RCC, RCC_UNKNOWN_VARIABLE);
2570 }
2571 }
2572 else
2573 {
2574 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
2575 }
2576
2577 sendMessage(&msg);
2578 }
2579
2580 /**
2581 * Close session
2582 */
2583 void ClientSession::kill()
2584 {
2585 notify(NX_NOTIFY_SESSION_KILLED);
2586
2587 // We shutdown socket connection, which will cause
2588 // read thread to stop, and other threads will follow
2589 shutdown(m_hSocket, 2);
2590 }
2591
2592 /**
2593 * Handler for new events
2594 */
2595 void ClientSession::onNewEvent(Event *pEvent)
2596 {
2597 UPDATE_INFO *pUpdate;
2598 NXCPMessage *msg;
2599 if (isAuthenticated() && (m_dwActiveChannels & NXC_CHANNEL_EVENTS) && (m_dwSystemAccess & SYSTEM_ACCESS_VIEW_EVENT_LOG))
2600 {
2601 NetObj *object = FindObjectById(pEvent->getSourceId());
2602 //If can't find object - just send to all events, if object found send to thous who have rights
2603 if (object == NULL || object->checkAccessRights(m_dwUserId, OBJECT_ACCESS_READ))
2604 {
2605 pUpdate = (UPDATE_INFO *)malloc(sizeof(UPDATE_INFO));
2606 pUpdate->dwCategory = INFO_CAT_EVENT;
2607 msg = new NXCPMessage;
2608 msg->setCode(CMD_EVENTLOG_RECORDS);
2609 pEvent->prepareMessage(msg);
2610 pUpdate->pData = msg;
2611 m_pUpdateQueue->Put(pUpdate);
2612 }
2613 }
2614 }
2615
2616 /**
2617 * Handler for object changes
2618 */
2619 void ClientSession::onObjectChange(NetObj *object)
2620 {
2621 UPDATE_INFO *pUpdate;
2622
2623 if (isAuthenticated() && (m_dwActiveChannels & NXC_CHANNEL_OBJECTS))
2624 if (object->isDeleted() || object->checkAccessRights(m_dwUserId, OBJECT_ACCESS_READ))
2625 {
2626 pUpdate = (UPDATE_INFO *)malloc(sizeof(UPDATE_INFO));
2627 pUpdate->dwCategory = INFO_CAT_OBJECT_CHANGE;
2628 pUpdate->pData = object;
2629 object->incRefCount();
2630 m_pUpdateQueue->Put(pUpdate);
2631 }
2632 }
2633
2634 /**
2635 * Send notification message to server
2636 */
2637 void ClientSession::notify(UINT32 dwCode, UINT32 dwData)
2638 {
2639 NXCPMessage msg;
2640
2641 msg.setCode(CMD_NOTIFY);
2642 msg.setField(VID_NOTIFICATION_CODE, dwCode);
2643 msg.setField(VID_NOTIFICATION_DATA, dwData);
2644 sendMessage(&msg);
2645 }
2646
2647 /**
2648 * Modify object
2649 */
2650 void ClientSession::modifyObject(NXCPMessage *pRequest)
2651 {
2652 UINT32 dwObjectId, dwResult = RCC_SUCCESS;
2653 NetObj *object;
2654 NXCPMessage msg;
2655
2656 // Prepare reply message
2657 msg.setCode(CMD_REQUEST_COMPLETED);
2658 msg.setId(pRequest->getId());
2659
2660 dwObjectId = pRequest->getFieldAsUInt32(VID_OBJECT_ID);
2661 object = FindObjectById(dwObjectId);
2662 if (object != NULL)
2663 {
2664 if (object->checkAccessRights(m_dwUserId, OBJECT_ACCESS_MODIFY))
2665 {
2666 // If user attempts to change object's ACL, check
2667 // if he has OBJECT_ACCESS_ACL permission
2668 if (pRequest->isFieldExist(VID_ACL_SIZE))
2669 if (!object->checkAccessRights(m_dwUserId, OBJECT_ACCESS_ACL))
2670 dwResult = RCC_ACCESS_DENIED;
2671
2672 // If user attempts to rename object, check object's name
2673 if (pRequest->isFieldExist(VID_OBJECT_NAME))
2674 {
2675 TCHAR name[256];
2676 pRequest->getFieldAsString(VID_OBJECT_NAME, name, 256);
2677 if (!IsValidObjectName(name, TRUE))
2678 dwResult = RCC_INVALID_OBJECT_NAME;
2679 }
2680
2681 // If allowed, change object and set completion code
2682 if (dwResult == RCC_SUCCESS)
2683 {
2684 dwResult = object->modifyFromMessage(pRequest);
2685 if (dwResult == RCC_SUCCESS)
2686 {
2687 object->postModify();
2688 }
2689 }
2690 msg.setField(VID_RCC, dwResult);
2691
2692 if (dwResult == RCC_SUCCESS)
2693 {
2694 WriteAuditLog(AUDIT_OBJECTS, TRUE, m_dwUserId, m_workstation, m_id, dwObjectId,
2695 _T("Object %s modified from client"), object->getName());
2696 }
2697 else
2698 {
2699 WriteAuditLog(AUDIT_OBJECTS, FALSE, m_dwUserId, m_workstation, m_id, dwObjectId,
2700 _T("Failed to modify object from client - error %d"), dwResult);
2701 }
2702 }
2703 else
2704 {
2705 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
2706 WriteAuditLog(AUDIT_OBJECTS, FALSE, m_dwUserId, m_workstation, m_id, dwObjectId,
2707 _T("Failed to modify object from client - access denied"), dwResult);
2708 }
2709 }
2710 else
2711 {
2712 msg.setField(VID_RCC, RCC_INVALID_OBJECT_ID);
2713 }
2714
2715 // Send response
2716 sendMessage(&msg);
2717 }
2718
2719 /**
2720 * Send users database to client
2721 */
2722 void ClientSession::sendUserDB(UINT32 dwRqId)
2723 {
2724 NXCPMessage msg;
2725 UserDatabaseObject **users;
2726 int i, userCount;
2727
2728 // Prepare response message
2729 msg.setCode(CMD_REQUEST_COMPLETED);
2730 msg.setId(dwRqId);
2731 msg.setField(VID_RCC, RCC_SUCCESS);
2732 sendMessage(&msg);
2733 msg.deleteAllFields();
2734
2735 // Send user database
2736 users = OpenUserDatabase(&userCount);
2737 for(i = 0; i < userCount; i++)
2738 {
2739 msg.setCode((users[i]->getId() & GROUP_FLAG) ? CMD_GROUP_DATA : CMD_USER_DATA);
2740 users[i]->fillMessage(&msg);
2741 sendMessage(&msg);
2742 msg.deleteAllFields();
2743 }
2744 CloseUserDatabase();
2745
2746 // Send end-of-database notification
2747 msg.setCode(CMD_USER_DB_EOF);
2748 sendMessage(&msg);
2749 }
2750
2751 /**
2752 * Create new user
2753 */
2754 void ClientSession::createUser(NXCPMessage *pRequest)
2755 {
2756 NXCPMessage msg;
2757
2758 // Prepare response message
2759 msg.setCode(CMD_REQUEST_COMPLETED);
2760 msg.setId(pRequest->getId());
2761
2762 // Check user rights
2763 if (!(m_dwSystemAccess & SYSTEM_ACCESS_MANAGE_USERS))
2764 {
2765 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
2766 }
2767 else if (!(m_dwFlags & CSF_USER_DB_LOCKED))
2768 {
2769 // User database have to be locked before any
2770 // changes to user database can be made
2771 msg.setField(VID_RCC, RCC_OUT_OF_STATE_REQUEST);
2772 }
2773 else
2774 {
2775 UINT32 dwResult, dwUserId;
2776 BOOL bIsGroup;
2777 TCHAR szUserName[MAX_USER_NAME];
2778
2779 pRequest->getFieldAsString(VID_USER_NAME, szUserName, MAX_USER_NAME);
2780 if (IsValidObjectName(szUserName))
2781 {
2782 bIsGroup = pRequest->getFieldAsUInt16(VID_IS_GROUP);
2783 dwResult = CreateNewUser(szUserName, bIsGroup, &dwUserId);
2784 msg.setField(VID_RCC, dwResult);
2785 if (dwResult == RCC_SUCCESS)
2786 {
2787 msg.setField(VID_USER_ID, dwUserId); // Send id of new user to client
2788 WriteAuditLog(AUDIT_SECURITY, TRUE, m_dwUserId, m_workstation, m_id, dwUserId, _T("%s %s created"), bIsGroup ? _T("Group") : _T("User"), szUserName);
2789 }
2790 }
2791 else
2792 {
2793 msg.setField(VID_RCC, RCC_INVALID_OBJECT_NAME);
2794 }
2795 }
2796
2797 // Send response
2798 sendMessage(&msg);
2799 }
2800
2801 /**
2802 * Update existing user's data
2803 */
2804 void ClientSession::updateUser(NXCPMessage *pRequest)
2805 {
2806 NXCPMessage msg;
2807
2808 // Prepare response message
2809 msg.setCode(CMD_REQUEST_COMPLETED);
2810 msg.setId(pRequest->getId());
2811
2812 // Check user rights
2813 if (!(m_dwSystemAccess & SYSTEM_ACCESS_MANAGE_USERS))
2814 {
2815 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
2816 }
2817 else if (!(m_dwFlags & CSF_USER_DB_LOCKED))
2818 {
2819 // User database have to be locked before any
2820 // changes to user database can be made
2821 msg.setField(VID_RCC, RCC_OUT_OF_STATE_REQUEST);
2822 }
2823 else
2824 {
2825 UINT32 result = ModifyUserDatabaseObject(pRequest);
2826 if (result == RCC_SUCCESS)
2827 {
2828 TCHAR name[MAX_DB_STRING];
2829 UINT32 id = pRequest->getFieldAsUInt32(VID_USER_ID);
2830 ResolveUserId(id, name, MAX_DB_STRING);
2831 WriteAuditLog(AUDIT_SECURITY, TRUE, m_dwUserId, m_workstation, m_id, id,
2832 _T("%s %s modified"), (id & GROUP_FLAG) ? _T("Group") : _T("User"), name);
2833 }
2834 msg.setField(VID_RCC, result);
2835 }
2836
2837 // Send response
2838 sendMessage(&msg);
2839 }
2840
2841 /**
2842 * Delete user
2843 */
2844 void ClientSession::deleteUser(NXCPMessage *pRequest)
2845 {
2846 NXCPMessage msg;
2847 UINT32 dwUserId;
2848
2849 // Prepare response message
2850 msg.setCode(CMD_REQUEST_COMPLETED);
2851 msg.setId(pRequest->getId());
2852
2853 // Check user rights
2854 if (!(m_dwSystemAccess & SYSTEM_ACCESS_MANAGE_USERS))
2855 {
2856 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
2857 }
2858 else if (!(m_dwFlags & CSF_USER_DB_LOCKED))
2859 {
2860 // User database have to be locked before any
2861 // changes to user database can be made
2862 msg.setField(VID_RCC, RCC_OUT_OF_STATE_REQUEST);
2863 }
2864 else
2865 {
2866 // Get Id of user to be deleted
2867 dwUserId = pRequest->getFieldAsUInt32(VID_USER_ID);
2868
2869 if ((dwUserId != 0) && (dwUserId != GROUP_EVERYONE))
2870 {
2871 if (!IsLoggedIn(dwUserId))
2872 {
2873 TCHAR name[MAX_DB_STRING];
2874 ResolveUserId(dwUserId, name, MAX_DB_STRING);
2875 UINT32 rcc = DeleteUserDatabaseObject(dwUserId);
2876 msg.setField(VID_RCC, rcc);
2877 if(rcc == RCC_SUCCESS)
2878 {
2879 WriteAuditLog(AUDIT_SECURITY, TRUE, m_dwUserId, m_workstation, m_id, dwUserId,
2880 _T("%s %s [%d] deleted"), (dwUserId & GROUP_FLAG) ? _T("Group") : _T("User"), name, dwUserId);
2881 }
2882 }
2883 else
2884 {
2885 // logger in users cannot be deleted
2886 msg.setField(VID_RCC, RCC_USER_LOGGED_IN);
2887 }
2888 }
2889 else
2890 {
2891 // System administrator account and everyone group cannot be deleted
2892 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
2893 }
2894 }
2895
2896 // Send response
2897 sendMessage(&msg);
2898 }
2899
2900 /**
2901 * Lock/unlock user database
2902 */
2903 void ClientSession::lockUserDB(UINT32 dwRqId, BOOL bLock)
2904 {
2905 NXCPMessage msg;
2906 TCHAR szBuffer[256];
2907
2908 // Prepare response message
2909 msg.setCode(CMD_REQUEST_COMPLETED);
2910 msg.setId(dwRqId);
2911
2912 if (m_dwSystemAccess & SYSTEM_ACCESS_MANAGE_USERS)
2913 {
2914 if (bLock)
2915 {
2916 if (!LockComponent(CID_USER_DB, m_id, m_szUserName, NULL, szBuffer))
2917 {
2918 msg.setField(VID_RCC, RCC_COMPONENT_LOCKED);
2919 msg.setField(VID_LOCKED_BY, szBuffer);
2920 }
2921 else
2922 {
2923 m_dwFlags |= CSF_USER_DB_LOCKED;
2924 msg.setField(VID_RCC, RCC_SUCCESS);
2925 }
2926 }
2927 else
2928 {
2929 if (m_dwFlags & CSF_USER_DB_LOCKED)
2930 {
2931 UnlockComponent(CID_USER_DB);
2932 m_dwFlags &= ~CSF_USER_DB_LOCKED;
2933 }
2934 msg.setField(VID_RCC, RCC_SUCCESS);
2935 }
2936 }
2937 else
2938 {
2939 // Current user has no rights for user account management
2940 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
2941 }
2942
2943 // Send response
2944 sendMessage(&msg);
2945 }
2946
2947 /**
2948 * Notify client on user database update
2949 */
2950 void ClientSession::onUserDBUpdate(int code, UINT32 id, UserDatabaseObject *object)
2951 {
2952 NXCPMessage msg;
2953
2954 if (isAuthenticated())
2955 {
2956 msg.setCode(CMD_USER_DB_UPDATE);
2957 msg.setId(0);
2958 msg.setField(VID_UPDATE_TYPE, (WORD)code);
2959
2960 switch(code)
2961 {
2962 case USER_DB_CREATE:
2963 case USER_DB_MODIFY:
2964 object->fillMessage(&msg);
2965 break;
2966 default:
2967 msg.setField(VID_USER_ID, id);
2968 break;
2969 }
2970
2971 sendMessage(&msg);
2972 }
2973 }
2974
2975 /**
2976 * Change management status for the object
2977 */
2978 void ClientSession::changeObjectMgmtStatus(NXCPMessage *pRequest)
2979 {
2980 NXCPMessage msg;
2981 UINT32 dwObjectId;
2982 NetObj *object;
2983
2984 // Prepare response message
2985 msg.setCode(CMD_REQUEST_COMPLETED);
2986 msg.setId(pRequest->getId());
2987
2988 // Get object id and check access rights
2989 dwObjectId = pRequest->getFieldAsUInt32(VID_OBJECT_ID);
2990 object = FindObjectById(dwObjectId);
2991 if (object != NULL)
2992 {
2993 if (object->checkAccessRights(m_dwUserId, OBJECT_ACCESS_MODIFY))
2994 {
2995 if ((object->getObjectClass() != OBJECT_TEMPLATE) &&
2996 (object->getObjectClass() != OBJECT_TEMPLATEGROUP) &&
2997 (object->getObjectClass() != OBJECT_TEMPLATEROOT))
2998 {
2999 BOOL bIsManaged = (BOOL)pRequest->getFieldAsUInt16(VID_MGMT_STATUS);
3000 object->setMgmtStatus(bIsManaged);
3001 msg.setField(VID_RCC, RCC_SUCCESS);
3002 WriteAuditLog(AUDIT_OBJECTS, TRUE, m_dwUserId, m_workstation, m_id, object->getId(),
3003 _T("Object %s set to %s state"), object->getName(), bIsManaged ? _T("managed") : _T("unmanaged"));
3004 }
3005 else
3006 {
3007 msg.setField(VID_RCC, RCC_INCOMPATIBLE_OPERATION);
3008 }
3009 }
3010 else
3011 {
3012 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
3013 }
3014 }
3015 else
3016 {
3017 msg.setField(VID_RCC, RCC_INVALID_OBJECT_ID);
3018 }
3019
3020 // Send response
3021 sendMessage(&msg);
3022 }
3023
3024 /**
3025 * Set user's password
3026 */
3027 void ClientSession::setPassword(NXCPMessage *pRequest)
3028 {
3029 NXCPMessage msg;
3030 UINT32 dwUserId;
3031
3032 // Prepare response message
3033 msg.setCode(CMD_REQUEST_COMPLETED);
3034 msg.setId(pRequest->getId());
3035
3036 dwUserId = pRequest->getFieldAsUInt32(VID_USER_ID);
3037
3038 if (((m_dwSystemAccess & SYSTEM_ACCESS_MANAGE_USERS) &&
3039 !((dwUserId == 0) && (m_dwUserId != 0))) || // Only administrator can change password for UID 0
3040 (dwUserId == m_dwUserId)) // User can change password for itself
3041 {
3042 UINT32 dwResult;
3043 TCHAR newPassword[1024], oldPassword[1024];
3044
3045 #ifdef UNICODE
3046 pRequest->getFieldAsString(VID_PASSWORD, newPassword, 256);
3047 if (pRequest->isFieldExist(VID_OLD_PASSWORD))
3048 pRequest->getFieldAsString(VID_OLD_PASSWORD, oldPassword, 256);
3049 #else
3050 pRequest->getFieldAsUtf8String(VID_PASSWORD, newPassword, 1024);
3051 if (pRequest->isFieldExist(VID_OLD_PASSWORD))
3052 pRequest->getFieldAsUtf8String(VID_OLD_PASSWORD, oldPassword, 1024);
3053 #endif
3054 else
3055 oldPassword[0] = 0;
3056 dwResult = SetUserPassword(dwUserId, newPassword, oldPassword, dwUserId == m_dwUserId);
3057 msg.setField(VID_RCC, dwResult);
3058
3059 if (dwResult == RCC_SUCCESS)
3060 {
3061 TCHAR userName[MAX_DB_STRING];
3062 ResolveUserId(dwUserId, userName, MAX_DB_STRING);
3063 WriteAuditLog(AUDIT_SECURITY, TRUE, m_dwUserId, m_workstation, m_id, 0, _T("Changed password for user %s"), userName);
3064 }
3065 }
3066 else
3067 {
3068 // Current user has no rights to change password for specific user
3069 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
3070 }
3071
3072 // Send response
3073 sendMessage(&msg);
3074 }
3075
3076 /**
3077 * Send node's DCIs to client and lock data collection settings
3078 */
3079 void ClientSession::openNodeDCIList(NXCPMessage *pRequest)
3080 {
3081 NXCPMessage msg;
3082 UINT32 dwObjectId;
3083 NetObj *object;
3084 BOOL bSuccess = FALSE;
3085 TCHAR szLockInfo[MAX_SESSION_NAME];
3086
3087 // Prepare response message
3088 msg.setCode(CMD_REQUEST_COMPLETED);
3089 msg.setId(pRequest->getId());
3090
3091 // Get node id and check object class and access rights
3092 dwObjectId = pRequest->getFieldAsUInt32(VID_OBJECT_ID);
3093 object = FindObjectById(dwObjectId);
3094 if (object != NULL)
3095 {
3096 if ((object->getObjectClass() == OBJECT_NODE) ||
3097 (object->getObjectClass() == OBJECT_CLUSTER) ||
3098 (object->getObjectClass() == OBJECT_MOBILEDEVICE) ||
3099 (object->getObjectClass() == OBJECT_TEMPLATE))
3100 {
3101 if (object->checkAccessRights(m_dwUserId, OBJECT_ACCESS_READ))
3102 {
3103 // Try to lock DCI list
3104 if (((Template *)object)->lockDCIList(m_id, m_szUserName, szLockInfo))
3105 {
3106 bSuccess = TRUE;
3107 msg.setField(VID_RCC, RCC_SUCCESS);
3108
3109 // modify list of open nodes DCI lists
3110 m_pOpenDCIList = (UINT32 *)realloc(m_pOpenDCIList, sizeof(UINT32) * (m_dwOpenDCIListSize + 1));
3111 m_pOpenDCIList[m_dwOpenDCIListSize] = dwObjectId;
3112 m_dwOpenDCIListSize++;
3113 }
3114 else
3115 {
3116 msg.setField(VID_RCC, RCC_COMPONENT_LOCKED);
3117 msg.setField(VID_LOCKED_BY, szLockInfo);
3118 }
3119 }
3120 else
3121 {
3122 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
3123 }
3124 }
3125 else
3126 {
3127 msg.setField(VID_RCC, RCC_INVALID_OBJECT_ID);
3128 }
3129 }
3130 else
3131 {
3132 msg.setField(VID_RCC, RCC_INVALID_OBJECT_ID);
3133 }
3134
3135 // Send response
3136 sendMessage(&msg);
3137
3138 // If DCI list was successfully locked, send it to client
3139 if (bSuccess)
3140 ((Template *)object)->sendItemsToClient(this, pRequest->getId());
3141 }
3142
3143 /**
3144 * Unlock node's data collection settings
3145 */
3146 void ClientSession::closeNodeDCIList(NXCPMessage *pRequest)
3147 {
3148 NXCPMessage msg;
3149 UINT32 dwObjectId;
3150 NetObj *object;
3151
3152 // Prepare response message
3153 msg.setCode(CMD_REQUEST_COMPLETED);
3154 msg.setId(pRequest->getId());
3155
3156 // Get node id and check object class and access rights
3157 dwObjectId = pRequest->getFieldAsUInt32(VID_OBJECT_ID);
3158 object = FindObjectById(dwObjectId);
3159 if (object != NULL)
3160 {
3161 if ((object->getObjectClass() == OBJECT_NODE) ||
3162 (object->getObjectClass() == OBJECT_CLUSTER) ||
3163 (object->getObjectClass() == OBJECT_MOBILEDEVICE) ||
3164 (object->getObjectClass() == OBJECT_TEMPLATE))
3165 {
3166 if (object->checkAccessRights(m_dwUserId, OBJECT_ACCESS_READ))
3167 {
3168 BOOL bSuccess;
3169
3170 // Try to unlock DCI list
3171 bSuccess = ((Template *)object)->unlockDCIList(m_id);
3172 msg.setField(VID_RCC, bSuccess ? RCC_SUCCESS : RCC_OUT_OF_STATE_REQUEST);
3173
3174 // modify list of open nodes DCI lists
3175 if (bSuccess)
3176 {
3177 UINT32 i;
3178
3179 for(i = 0; i < m_dwOpenDCIListSize; i++)
3180 if (m_pOpenDCIList[i] == dwObjectId)
3181 {
3182 m_dwOpenDCIListSize--;
3183 memmove(&m_pOpenDCIList[i], &m_pOpenDCIList[i + 1], sizeof(UINT32) * (m_dwOpenDCIListSize - i));
3184 break;
3185 }
3186 }
3187
3188 // Queue template update
3189 if ((object->getObjectClass() == OBJECT_TEMPLATE) || (object->getObjectClass() == OBJECT_CLUSTER))
3190 ((Template *)object)->queueUpdate();
3191 }
3192 else
3193 {
3194 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
3195 }
3196 }
3197 else
3198 {
3199 msg.setField(VID_RCC, RCC_INVALID_OBJECT_ID);
3200 }
3201 }
3202 else
3203 {
3204 msg.setField(VID_RCC, RCC_INVALID_OBJECT_ID);
3205 }
3206
3207 // Send response
3208 sendMessage(&msg);
3209 }
3210
3211 /**
3212 * Create, modify, or delete data collection item for node
3213 */
3214 void ClientSession::modifyNodeDCI(NXCPMessage *pRequest)
3215 {
3216 NXCPMessage msg;
3217 UINT32 dwObjectId;
3218 NetObj *object;
3219
3220 // Prepare response message
3221 msg.setCode(CMD_REQUEST_COMPLETED);
3222 msg.setId(pRequest->getId());
3223
3224 // Get node id and check object class and access rights
3225 dwObjectId = pRequest->getFieldAsUInt32(VID_OBJECT_ID);
3226 object = FindObjectById(dwObjectId);
3227 if (object != NULL)
3228 {
3229 if ((object->getObjectClass() == OBJECT_NODE) ||
3230 (object->getObjectClass() == OBJECT_CLUSTER) ||
3231 (object->getObjectClass() == OBJECT_MOBILEDEVICE) ||
3232 (object->getObjectClass() == OBJECT_TEMPLATE))
3233 {
3234 if (((Template *)object)->isLockedBySession(m_id))
3235 {
3236 if (object->checkAccessRights(m_dwUserId, OBJECT_ACCESS_MODIFY))
3237 {
3238 UINT32 i, dwItemId, dwNumMaps, *pdwMapId, *pdwMapIndex;
3239 DCObject *dcObject;
3240 BOOL bSuccess = FALSE;
3241
3242 int dcObjectType = (int)pRequest->getFieldAsUInt16(VID_DCOBJECT_TYPE);
3243 switch(pRequest->getCode())
3244 {
3245 case CMD_CREATE_NEW_DCI:
3246 // Create dummy DCI
3247 switch(dcObjectType)
3248 {
3249 case DCO_TYPE_ITEM:
3250 dcObject = new DCItem(CreateUniqueId(IDG_ITEM), _T("no name"), DS_INTERNAL, DCI_DT_INT,
3251 ConfigReadInt(_T("DefaultDCIPollingInterval"), 60),
3252 ConfigReadInt(_T("DefaultDCIRetentionTime"), 30), (Node *)object);
3253 break;
3254 case DCO_TYPE_TABLE:
3255 dcObject = new DCTable(CreateUniqueId(IDG_ITEM), _T("no name"), DS_INTERNAL,
3256 ConfigReadInt(_T("DefaultDCIPollingInterval"), 60),
3257 ConfigReadInt(_T("DefaultDCIRetentionTime"), 30), (Node *)object);
3258 break;
3259 default:
3260 dcObject = NULL;
3261 break;
3262 }
3263 if (dcObject != NULL)
3264 {
3265 dcObject->setStatus(ITEM_STATUS_DISABLED, false);
3266 if ((bSuccess = ((Template *)object)->addDCObject(dcObject)))
3267 {
3268 msg.setField(VID_RCC, RCC_SUCCESS);
3269 // Return new item id to client
3270 msg.setField(VID_DCI_ID, dcObject->getId());
3271 }
3272 else // Unable to add item to node
3273 {
3274 delete dcObject;
3275 msg.setField(VID_RCC, RCC_DUPLICATE_DCI);
3276 }
3277 }
3278 else
3279 {
3280 msg.setField(VID_RCC, RCC_INVALID_ARGUMENT);
3281 }
3282 break;
3283 case CMD_MODIFY_NODE_DCI:
3284 dwItemId = pRequest->getFieldAsUInt32(VID_DCI_ID);
3285 bSuccess = ((Template *)object)->updateDCObject(dwItemId, pRequest, &dwNumMaps, &pdwMapIndex, &pdwMapId);
3286 if (bSuccess)
3287 {
3288 msg.setField(VID_RCC, RCC_SUCCESS);
3289
3290 // Send index to id mapping for newly created thresholds to client
3291 if (dcObjectType == DCO_TYPE_ITEM)
3292 {
3293 msg.setField(VID_DCI_NUM_MAPS, dwNumMaps);
3294 for(i = 0; i < dwNumMaps; i++)
3295 {
3296 pdwMapId[i] = htonl(pdwMapId[i]);
3297 pdwMapIndex[i] = htonl(pdwMapIndex[i]);
3298 }
3299 msg.setField(VID_DCI_MAP_IDS, (BYTE *)pdwMapId, sizeof(UINT32) * dwNumMaps);
3300 msg.setField(VID_DCI_MAP_INDEXES, (BYTE *)pdwMapIndex, sizeof(UINT32) * dwNumMaps);
3301 safe_free(pdwMapId);
3302 safe_free(pdwMapIndex);
3303 }
3304 }
3305 else
3306 {
3307 msg.setField(VID_RCC, RCC_INVALID_DCI_ID);
3308 }
3309 break;
3310 case CMD_DELETE_NODE_DCI:
3311 dwItemId = pRequest->getFieldAsUInt32(VID_DCI_ID);
3312 bSuccess = ((Template *)object)->deleteDCObject(dwItemId, true);
3313 msg.setField(VID_RCC, bSuccess ? RCC_SUCCESS : RCC_INVALID_DCI_ID);
3314 break;
3315 }
3316 if (bSuccess)
3317 ((Template *)object)->setDCIModificationFlag();
3318 }
3319 else // User doesn't have MODIFY rights on object
3320 {
3321 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
3322 }
3323 }
3324 else // Nodes DCI list not locked by this session
3325 {
3326 msg.setField(VID_RCC, RCC_OUT_OF_STATE_REQUEST);
3327 }
3328 }
3329 else // Object is not a node
3330 {
3331 msg.setField(VID_RCC, RCC_INVALID_OBJECT_ID);
3332 }
3333 }
3334 else // No object with given ID
3335 {
3336 msg.setField(VID_RCC, RCC_INVALID_OBJECT_ID);
3337 }
3338
3339 // Send response
3340 sendMessage(&msg);
3341 }
3342
3343 /**
3344 * Change status for one or more DCIs
3345 */
3346 void ClientSession::changeDCIStatus(NXCPMessage *pRequest)
3347 {
3348 NXCPMessage msg;
3349 NetObj *object;
3350
3351 // Prepare response message
3352 msg.setCode(CMD_REQUEST_COMPLETED);
3353 msg.setId(pRequest->getId());
3354
3355 // Get node id and check object class and access rights
3356 object = FindObjectById(pRequest->getFieldAsUInt32(VID_OBJECT_ID));
3357 if (object != NULL)
3358 {
3359 if ((object->getObjectClass() == OBJECT_NODE) ||
3360 (object->getObjectClass() == OBJECT_CLUSTER) ||
3361 (object->getObjectClass() == OBJECT_MOBILEDEVICE) ||
3362 (object->getObjectClass() == OBJECT_TEMPLATE))
3363 {
3364 if (((Template *)object)->isLockedBySession(m_id))
3365 {
3366 if (object->checkAccessRights(m_dwUserId, OBJECT_ACCESS_MODIFY))
3367 {
3368 UINT32 dwNumItems, *pdwItemList;
3369 int iStatus;
3370
3371 iStatus = pRequest->getFieldAsUInt16(VID_DCI_STATUS);
3372 dwNumItems = pRequest->getFieldAsUInt32(VID_NUM_ITEMS);
3373 pdwItemList = (UINT32 *)malloc(sizeof(UINT32) * dwNumItems);
3374 pRequest->getFieldAsInt32Array(VID_ITEM_LIST, dwNumItems, pdwItemList);
3375 if (((Template *)object)->setItemStatus(dwNumItems, pdwItemList, iStatus))
3376 msg.setField(VID_RCC, RCC_SUCCESS);
3377 else
3378 msg.setField(VID_RCC, RCC_INVALID_DCI_ID);
3379 free(pdwItemList);
3380 }
3381 else // User doesn't have MODIFY rights on object
3382 {
3383 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
3384 }
3385 }
3386 else // Nodes DCI list not locked by this session
3387 {
3388 msg.setField(VID_RCC, RCC_OUT_OF_STATE_REQUEST);
3389 }
3390 }
3391 else // Object is not a node
3392 {
3393 msg.setField(VID_RCC, RCC_INCOMPATIBLE_OPERATION);
3394 }
3395 }
3396 else // No object with given ID
3397 {
3398 msg.setField(VID_RCC, RCC_INVALID_OBJECT_ID);
3399 }
3400
3401 // Send response
3402 sendMessage(&msg);
3403 }
3404
3405 /**
3406 * Clear all collected data for DCI
3407 */
3408 void ClientSession::clearDCIData(NXCPMessage *pRequest)
3409 {
3410 NXCPMessage msg;
3411 NetObj *object;
3412 UINT32 dwItemId;
3413
3414 // Prepare response message
3415 msg.setCode(CMD_REQUEST_COMPLETED);
3416 msg.setId(pRequest->getId());
3417
3418 // Get node id and check object class and access rights
3419 object = FindObjectById(pRequest->getFieldAsUInt32(VID_OBJECT_ID));
3420 if (object != NULL)
3421 {
3422 if ((object->getObjectClass() == OBJECT_NODE) || (object->getObjectClass() == OBJECT_MOBILEDEVICE) || (object->getObjectClass() == OBJECT_CLUSTER))
3423 {
3424 if (object->checkAccessRights(m_dwUserId, OBJECT_ACCESS_DELETE))
3425 {
3426 dwItemId = pRequest->getFieldAsUInt32(VID_DCI_ID);
3427 debugPrintf(4, _T("ClearDCIData: request for DCI %d at node %d"), dwItemId, object->getId());
3428 DCObject *dci = ((Template *)object)->getDCObjectById(dwItemId);
3429 if (dci != NULL)
3430 {
3431 msg.setField(VID_RCC, dci->deleteAllData() ? RCC_SUCCESS : RCC_DB_FAILURE);
3432 debugPrintf(4, _T("ClearDCIData: DCI %d at node %d"), dwItemId, object->getId());
3433 }
3434 else
3435 {
3436 msg.setField(VID_RCC, RCC_INVALID_DCI_ID);
3437 debugPrintf(4, _T("ClearDCIData: DCI %d at node %d not found"), dwItemId, object->getId());
3438 }
3439 }
3440 else // User doesn't have DELETE rights on object
3441 {
3442 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
3443 }
3444 }
3445 else // Object is not a node
3446 {
3447 msg.setField(VID_RCC, RCC_INCOMPATIBLE_OPERATION);
3448 }
3449 }
3450 else // No object with given ID
3451 {
3452 msg.setField(VID_RCC, RCC_INVALID_OBJECT_ID);
3453 }
3454
3455 // Send response
3456 sendMessage(&msg);
3457 }
3458
3459 /**
3460 * Copy or move DCI from one node or template to another
3461 */
3462 void ClientSession::copyDCI(NXCPMessage *pRequest)
3463 {
3464 NXCPMessage msg;
3465 NetObj *pSource, *pDestination;
3466 TCHAR szLockInfo[MAX_SESSION_NAME];
3467 BOOL bMove;
3468
3469 // Prepare response message
3470 msg.setCode(CMD_REQUEST_COMPLETED);
3471 msg.setId(pRequest->getId());
3472
3473 // Get source and destination
3474 pSource = FindObjectById(pRequest->getFieldAsUInt32(VID_SOURCE_OBJECT_ID));
3475 pDestination = FindObjectById(pRequest->getFieldAsUInt32(VID_DESTINATION_OBJECT_ID));
3476 if ((pSource != NULL) && (pDestination != NULL))
3477 {
3478 // Check object types
3479 if (((pSource->getObjectClass() == OBJECT_NODE) || (pSource->getObjectClass() == OBJECT_MOBILEDEVICE) || (pSource->getObjectClass() == OBJECT_TEMPLATE) || (pSource->getObjectClass() == OBJECT_CLUSTER)) &&
3480 ((pDestination->getObjectClass() == OBJECT_NODE) || (pDestination->getObjectClass() == OBJECT_MOBILEDEVICE) || (pDestination->getObjectClass() == OBJECT_TEMPLATE) || (pDestination->getObjectClass() == OBJECT_CLUSTER)))
3481 {
3482 if (((Template *)pSource)->isLockedBySession(m_id))
3483 {
3484 bMove = pRequest->getFieldAsUInt16(VID_MOVE_FLAG);
3485 // Check access rights
3486 if ((pSource->checkAccessRights(m_dwUserId, bMove ? (OBJECT_ACCESS_READ | OBJECT_ACCESS_MODIFY) : OBJECT_ACCESS_READ)) &&
3487 (pDestination->checkAccessRights(m_dwUserId, OBJECT_ACCESS_MODIFY)))
3488 {
3489 // Attempt to lock destination's DCI list
3490 if ((pDestination->getId() == pSource->getId()) ||
3491 (((Template *)pDestination)->lockDCIList(m_id, m_szUserName, szLockInfo)))
3492 {
3493 UINT32 i, *pdwItemList, dwNumItems;
3494 const DCObject *pSrcItem;
3495 DCObject *pDstItem;
3496 int iErrors = 0;
3497
3498 // Get list of items to be copied/moved
3499 dwNumItems = pRequest->getFieldAsUInt32(VID_NUM_ITEMS);
3500 pdwItemList = (UINT32 *)malloc(sizeof(UINT32) * dwNumItems);
3501 pRequest->getFieldAsInt32Array(VID_ITEM_LIST, dwNumItems, pdwItemList);
3502
3503 // Copy items
3504 for(i = 0; i < dwNumItems; i++)
3505 {
3506 pSrcItem = ((Template *)pSource)->getDCObjectById(pdwItemList[i]);
3507 if (pSrcItem != NULL)
3508 {
3509 switch(pSrcItem->getType())
3510 {
3511 case DCO_TYPE_ITEM:
3512 pDstItem = new DCItem((DCItem *)pSrcItem);
3513 break;
3514 case DCO_TYPE_TABLE:
3515 pDstItem = new DCTable((DCTable *)pSrcItem);
3516 break;
3517 default:
3518 pDstItem = NULL;
3519 break;
3520 }
3521 if (pDstItem != NULL)
3522 {
3523 pDstItem->setTemplateId(0, 0);
3524 pDstItem->changeBinding(CreateUniqueId(IDG_ITEM),
3525 (Template *)pDestination, FALSE);
3526 if (((Template *)pDestination)->addDCObject(pDstItem))
3527 {
3528 if (bMove)
3529 {
3530 // Delete original item
3531 if (!((Template *)pSource)->deleteDCObject(pdwItemList[i], TRUE))
3532 {
3533 iErrors++;
3534 }
3535 }
3536 }
3537 else
3538 {
3539 delete pDstItem;
3540 iErrors++;
3541 }
3542 }
3543 else
3544 {
3545 DbgPrintf(2, _T("INTERNAL ERROR: ClientSession::CopyDCI(): unknown DCO type %d"), pSrcItem->getType());
3546 iErrors++;
3547 }
3548 }
3549 else
3550 {
3551 iErrors++;
3552 }
3553 }
3554
3555 // Cleanup
3556 free(pdwItemList);
3557 if (pDestination->getId() != pSource->getId())
3558 ((Template *)pDestination)->unlockDCIList(m_id);
3559 msg.setField(VID_RCC, (iErrors == 0) ? RCC_SUCCESS : RCC_DCI_COPY_ERRORS);
3560
3561 // Queue template update
3562 if (pDestination->getObjectClass() == OBJECT_TEMPLATE)
3563 ((Template *)pDestination)->queueUpdate();
3564 }
3565 else // Destination's DCI list already locked by someone else
3566 {
3567 msg.setField(VID_RCC, RCC_COMPONENT_LOCKED);
3568 msg.setField(VID_LOCKED_BY, szLockInfo);
3569 }
3570 }
3571 else // User doesn't have enough rights on object(s)
3572 {
3573 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
3574 }
3575 }
3576 else // Source node DCI list not locked by this session
3577 {
3578 msg.setField(VID_RCC, RCC_OUT_OF_STATE_REQUEST);
3579 }
3580 }
3581 else // Object(s) is not a node
3582 {
3583 msg.setField(VID_RCC, RCC_INVALID_OBJECT_ID);
3584 }
3585 }
3586 else // No object(s) with given ID
3587 {
3588 msg.setField(VID_RCC, RCC_INVALID_OBJECT_ID);
3589 }
3590
3591 // Send response
3592 sendMessage(&msg);
3593 }
3594
3595 /**
3596 * Send list of thresholds for DCI
3597 */
3598 void ClientSession::sendDCIThresholds(NXCPMessage *request)
3599 {
3600 NXCPMessage msg;
3601 NetObj *object;
3602
3603 // Prepare response message
3604 msg.setCode(CMD_REQUEST_COMPLETED);
3605 msg.setId(request->getId());
3606
3607 // Get node id and check object class and access rights
3608 object = FindObjectById(request->getFieldAsUInt32(VID_OBJECT_ID));
3609 if (object != NULL)
3610 {
3611 if (object->checkAccessRights(m_dwUserId, OBJECT_ACCESS_READ))
3612 {
3613 if ((object->getObjectClass() == OBJECT_NODE) || (object->getObjectClass() == OBJECT_MOBILEDEVICE) || (object->getObjectClass() == OBJECT_CLUSTER))
3614 {
3615 DCObject *dci = ((Template *)object)->getDCObjectById(request->getFieldAsUInt32(VID_DCI_ID));
3616 if ((dci != NULL) && (dci->getType() == DCO_TYPE_ITEM))
3617 {
3618 ((DCItem *)dci)->fillMessageWithThresholds(&msg);
3619 msg.setField(VID_RCC, RCC_SUCCESS);
3620 }
3621 else
3622 {
3623 msg.setField(VID_RCC, RCC_INVALID_DCI_ID);
3624 }
3625 }
3626 else
3627 {
3628 msg.setField(VID_RCC, RCC_INCOMPATIBLE_OPERATION);
3629 }
3630 }
3631 else
3632 {
3633 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
3634 }
3635 }
3636 else // No object with given ID
3637 {
3638 msg.setField(VID_RCC, RCC_INVALID_OBJECT_ID);
3639 }
3640
3641 // Send response
3642 sendMessage(&msg);
3643 }
3644
3645 /**
3646 * Prepare statement for reading data from idata table
3647 */
3648 static DB_STATEMENT PrepareIDataSelect(DB_HANDLE hdb, UINT32 nodeId, UINT32 maxRows, const TCHAR *condition)
3649 {
3650 TCHAR query[512];
3651
3652 switch(g_dbSyntax)
3653 {
3654 case DB_SYNTAX_MSSQL:
3655 _sntprintf(query, 512, _T("SELECT TOP %d idata_timestamp,idata_value FROM idata_%d WHERE item_id=?%s ORDER BY idata_timestamp DESC"),
3656 (int)maxRows, (int)nodeId, condition);
3657 break;
3658 case DB_SYNTAX_ORACLE:
3659 _sntprintf(query, 512, _T("SELECT * FROM (SELECT idata_timestamp,idata_value FROM idata_%d WHERE item_id=?%s ORDER BY idata_timestamp DESC) WHERE ROWNUM<=%d"),
3660 (int)nodeId, condition, (int)maxRows);
3661 break;
3662 case DB_SYNTAX_MYSQL:
3663 case DB_SYNTAX_PGSQL:
3664 case DB_SYNTAX_SQLITE:
3665 _sntprintf(query, 512, _T("SELECT idata_timestamp,idata_value FROM idata_%d WHERE item_id=?%s ORDER BY idata_timestamp DESC LIMIT %d"),
3666 (int)nodeId, condition, (int)maxRows);
3667 break;
3668 case DB_SYNTAX_DB2:
3669 _sntprintf(query, 512, _T("SELECT idata_timestamp,idata_value FROM idata_%d WHERE item_id=?%s ORDER BY idata_timestamp DESC FETCH FIRST %d ROWS ONLY"),
3670 (int)nodeId, condition, (int)maxRows);
3671 break;
3672 default:
3673 DbgPrintf(1, _T(">>> INTERNAL ERROR: unsupported database in PrepareIDataSelect"));
3674 return NULL; // Unsupported database
3675 }
3676 return DBPrepare(hdb, query);
3677 }
3678
3679 /**
3680 * Prepare statement for reading data from tdata table
3681 */
3682 static DB_STATEMENT PrepareTDataSelect(DB_HANDLE hdb, UINT32 nodeId, UINT32 maxRows, const TCHAR *condition)
3683 {
3684 TCHAR query[1024];
3685
3686 switch(g_dbSyntax)
3687 {
3688 case DB_SYNTAX_MSSQL:
3689 _sntprintf(query, 1024,
3690 _T("SELECT TOP %d d.tdata_timestamp, r.value FROM tdata_%d d")
3691 _T(" INNER JOIN tdata_records_%d rec ON rec.record_id=d.record_id ")
3692 _T("