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